You’ve created your own application, it works like a charm and you’re very proud of it. Yet installing this application on a different machine requires you to manually copy over files, a VCS checkout, manual configuration or other operations that are still open human to error.
This post describes a method of creating a simple Debian package using dpkg. The focus will be on the creation of a .deb package containing files (pre-compiled), post-installation and removal script, and dpkg-reconfigure support in combination with debconf. At the end of this brief guide you will have a .deb package that can be installed and reconfigured using ‘dpkg -i mycustompackage.deb’ and ‘dpkg-reconfigure mycustompackage’.
This post does not cover how to build a package using the official Debian way, including sources, documentation and package checking using lintian or piuparts. Please refer to the full how to package for Debian guide if you are looking for that specific information.
Creating packages requires the following packages to be installed:
Preparing your package
The basic idea is that a given directory is built into a .deb package. This directory contains all the files required for the installation, as well as a separate ‘DEBIAN’ folder that contains any scripts or files required for dpkg. Let’s start out with the directory itself before diving in deeper.
The directory needs to follow a certain naming convention. The directory name should start with the package name, followed by a dash and then the version number. For example, “lswhelloworld-1.0”.
This directory should contain the ‘DEBIAN’ folder for dpkg and any other files that you wish the package should contain. Note that all the files will be installed at the same given location. For example, if you create a script at “lswhelloworld-1.0/usr/bin/helloworld”, the file will be located at “/usr/bin/” after installation. Dpkg will also take care of removing the files when you uninstall the package.
After you have placed all the required files at the correct location, lets move on to the files within the ‘DEBIAN’ folder.
The most important file is the control file and should be located at “lswhelloworld-1.0/DEBIAN/control”. This file contains all the information that dpkg needs to install your package correctly. This is the place where you should define your package name, version (followed by packaging number), architecture, dependencies and basic description of your package.
Lets look at a small example, which includes the minimum required fields to get it to work. There is an extensive explanation about the control file for binary packages available for people that want to learn more about the control file.
Package: lswhelloworld Version: 1.0-1 Section: base Priority: optional Architecture: all Depends: debconf (>= 0.2.26) Maintainer: Rene van Aerle <firstname.lastname@example.org> Description: Hello World! Say hello to the user.
The main thing to look for is the Depends field, this field lets you setup the dependencies for your package. In our case we will depend on debconf version 0.2.26 or higher.
The config file, located at “lswhelloworld-1.0/DEBIAN/config” will be run right after the package has been installed or when it is being pre- or re-configured. In the config script we can ask the user questions that may be used during installation. We could use bash to read user input as described on tldp.org, but in general it is advised to use debconf for asking the user questions.
Debconf offers graphical package configuration and stores all the answers within a database. This database of answers can then be used for future reference and thus the values can be re-used in the pre-installation, post-installation, pre-removal and post-removal scripts without bothering the user with the same questions again. Only the dpkg-reconfigure command will re-ask the user questions.
Everytime you want to ask the user a question, you will need to add a template to the templates file, located at “lswhelloworld-1.0/DEBIAN/templates”.
Template: packagename/question1 Type: [select,multiselect,string,boolean,note,text,password] Default: [an optional default value] Description: Blah blah blah? Blah blah blah. Blah blah. Blah blah blah. Blah blah? Blah blah blah blah. Blah blah blah. Blah blah. . Blah blah blah. Blah blah. Blah blah blah. Blah blah. Blah blah blah. blah. Template: packagename/question2 ....
All your questions should be included, each identified with a unique template name (in example above: “packagename/questionX”). The type obviously depends on your question. The available data types include:
- string – holds any arbitrary string of data
- select – holds one of a finite number of possible values. These values must be specified in a field named Choices. Separate the possible values with commas and spaces, like this, Choices: yes, no, maybe
- multiselect – just like the select data type, except the user can choose any number of items from the list. This means that the Default field and the actual value of the question may be a comma and space delimited list of values, just like the Choices field.
- boolean – holds “true” or “false”
- note – this template is a note that can be displayed to the user. As opposed to text, it is something important that the user really should see. If debconf is not running interactively, it might be saved to a log file or mailbox for them to see later.
- text – this template is a scrap of text that can be displayed to the user. It’s intended to be used for mostly cosmetic reasons, touching up around other questions that are asked at the same time. Unlike a note, it isn’t treated as something the user should definitely see. Less complex front-ends may refuse to ever display this type of element.
- password – holds a password. Use with caution. Be aware that the password the user enters will be written to debconf’s database. You should consider clearing that value out of the database as soon as is possible.
After you’ve created your templates, you can use debconf to ask the questions in the config file. Note that it is advised to only ask questions within the config file and to do any other operation within the post/pre-installation or post/pre-removal scripts.
The example config script below asks the user 2 questions using debconf.
#!/bin/sh # Exit on error set -e # Source debconf library. . /usr/share/debconf/confmodule # Ask questions db_input low packagename/question1 || true db_input low packagename/question2 || true # Show interface db_go || true
First we include the debconf library and then prepare the questions using ‘db_input’. The priority is set so that the user can skip some questions according to the priority used with the dpkg command and fallback to the default values. (see: Ubuntu Manpage on dpkg-reconfigure)
Debian preinst, postinst, prerm, postrm scripts
The debian scripts are automatically run before or after a package is installed or removed. Along with the file named control, all these files are part of the control section of a debian archive and should be located in the ‘DEBIAN’ folder. For example, the post-installation script will be located at “lswhelloworld-1.0/DEBIAN/postinst”. The following scripts can be created (make sure the files are executeable, ‘chmod 0755’):
- preinst – this script executes before that package will be unpacked from its Debian archive (“.deb”) file. Many ‘preinst’ scripts stop services for packages which are being upgraded until their installation or upgrade is completed (following the successful execution of the ‘postinst’ script).
- postinst – this script typically completes any required configuration of the package foo once it has been unpacked from its Debian archive (“.deb”) file. Often ‘postinst’ scripts ask the user for input, and/or warn the user that if they accept the default values, they should remember to go back and re-configure that package as the situation warrants. Many ‘postinst’ scripts then execute any commands necessary to start or restart a service once a new package has been installed or upgraded.
- prerm – this script typically stops any daemons which are associated with a package. It is executed before the removal of files associated with the package.
- postrm – this script typically modifies links or other files associated with foo, and/or removes files created by the package.
Any of the above scripts can query the debconf database and take the appropriate action. To read the answers from the debconf database, you can use the following example code:
#!/bin/sh # Source debconf library. . /usr/share/debconf/confmodule # Fetching configuration from debconf db_get packagename/question1 ANSWER1=$RET db_get packagename/question2 ANSWER2=$RET
Again we include the debconf library and then use ‘db_get’ to fetch the answer from the debconf database. The value is then stored with the $RET variable. After creating your scripts, it is possible to build the package.
Building the package
To build the package, make sure the debian scripts (config, preinst, postinst, prerm, postrm) have the correct permissions (0755) and make sure the control and templates files are present within the ‘DEBIAN’ folder.
- control (required)
- templates (optional)
- preinst (optional, chmod 0755)
- postinst (optional, chmod 0755)
- prerm (optional, chmod 0755)
- postrm (optional, chmod 0755)
- … (files to be installed at specified location)
If you have all the files in place, you can build the package using ‘dpkg-deb –build’.
rene@ubuntu:~# dpkg-deb --build lswhelloworld-1.0/ dpkg-deb: building package `lswhelloworld' in `./lswhelloworld-1.0.deb'.
This will generate a .deb package that can be installed using ‘dpkg -i lswhelloworld-1.0.deb’ and will run the config and scripts accordingly. You can re-run the config by using ‘dpkg-reconfigure lswhelloworld’ or completely remove it ‘dpkg -r lswhelloworld’.
If you need help in building any of these packages, please leave your comment below.