2. Packaging software#

This chapter describes how software for UCS is packaged. For more details on packaging software in the Debian format, see Debian packaging.

2.1. Introduction#

UCS is based on the Debian distribution, that uses the deb format to package software. The program dpkg is used for handling a set of packages. On installation packages are unpacked and configured, while on un-installation packages are de-configured and the files belonging to the packages are removed from the system.

On top of that the apt-tools provide a software repository, which allows software to be downloaded from central file servers.

Package files provide an index of all packages contained in the repository, which is used to resolve dependencies between packages. While dpkg works on a set of packages given on the command line, apt-get builds that set of packages and their dependencies before invoking dpkg on this set. apt-get is a command line tool, which is fully described in its manual page apt-get(8). A more modern version with a text based user interface is aptitude, while synaptic provides a graphical frontend.

On UCS systems the administrator is not supposed to use these tools directly. Instead all software maintenance can be done through the UMC, which maps the requests to invocations of the commands given above.

2.2. Preparations#

This chapter describes some simple examples using existing packages. For downloading and building them, some packages must be installed on the system used as a development system:

  • git is used to checkout the source files belonging to the packages.

  • build-essential must be installed for building the package.

  • devscripts provides some useful tools for maintaining packages.

This can be achieved by running the following command:

$ sudo apt-get install git build-essential devscripts

2.3. Example: Re-building an UCS package#

Source code: UCS source: doc/developer-reference/packaging/testdeb/

2.3.1. Checking out and building a UCS package#

  1. Create the top level working directory

    $ mkdir work
    $ cd work/
    
  2. Either fetch the latest source code from the GIT version control system or download the source code of the currently packaged version.

    • Checkout example package from GIT version control system:

      $ git clone https://github.com/univention/univention-corporate-server.git
      $ cd univention-corporate-server/base/univention-ssh
      
    • Fetch the source code from the Univention Repository server:

      1. Enable the source repository once:

        $ sudo ucr set repository/online/sources=yes
        $ sudo apt-get update
        
      2. Fetch source code:

        $ apt-get source univention-ssh
        $ cd univention-ssh-*/
        
  3. Increment the version number of package to define a newer package:

    $ debchange --local work 'Private package rebuild'
    
  4. Install the required build dependencies

    $ sudo apt-get build-dep .
    
  5. Build the binary package

    $ dpkg-buildpackage -uc -us -b -rfakeroot
    
  6. Locally install the new binary package

    $ sudo apt-get install ../univention-ssh_*_*.deb
    

2.4. Example: Creating a new UCS package#

The following example provides a walk-through for packaging a Python script called testdeb.py. It creates a file testdeb-DATE-time in the /tmp/ directory.

A directory needs to be created for each source package, which hosts all other files and sub-directories.

$ mkdir testdeb-0.1
$ cd testdeb-0.1

The file testdeb.py, which is the program to be installed, will be put into that directory.

#!/usr/bin/python3
"""
Example for creating UCS packages.
"""

from datetime import datetime

if __name__ == "__main__":
   now = datetime.now()
   filename = "/tmp/testdeb-{:%y%m%d%H%M}".format(now)
   with open(filename, "a") as tmpfile:
      pass

In addition to the files to be installed, some metadata needs to be created in the debian/ sub-directory. This directory contains several files, which are needed to build a Debian package. The files and their format will be described in the following sections.

To create an initial debian/ directory with all template files, invoke the dh_make(1) command provided by the package dh-make:

$ dh_make --native --single --email user@example.com

Here several options are given to create the files for a source package, which contains all files in one archive and only creates one binary package at the end of the build process. More details are given in dh_make.

The program will output the following information:

Maintainer name  : John Doe
Email-Address    : user@example.com
Date             : Thu, 28 Feb 2013 08:11:30 +0100
Package Name     : testdeb
Version          : 0.1
License          : blank
Type of Package  : Single
Hit <enter> to confirm:

The package name testdeb and version 0.1 were determined from the name of the directory testdeb-0.1, the maintainer name and address were gathered from the UNIX account information.

After pressing the Enter key some warning message will be shown:

Currently there is no top level Makefile. This may require additional
tuning. Done. Please edit the files in the debian/ subdirectory now.
You should also check that the testdeb Makefiles install into $DESTDIR
and not in / .

Since this example is created from scratch, the missing Makefile is normal and this warning can be ignored. Instead of writing a Makefile to install the single executable, dh_install will be used later to install the file.

Since the command completed successfully, several files were created in the debian/ directory. Most of them are template files, which are unused in this example. To improve understandability they are deleted:

$ rm debian/*.ex debian/*.EX
$ rm debian/README* debian/doc

The remaining files are required and control the build process of all binary packages. Most of them don’t need to be modified for this example, but others must be completed using an editor.

debian/control

The file contains general information about the source and binary packages. It needs to be modified to include a description and contain the right build dependencies:

Source: testdeb
Section: univention
Priority: optional
Maintainer: John Doe <user@example.com>
Build-Depends:
  debhelper-compat (= 12),
Standards-Version: 4.3.0.3

Package: testdeb
Architecture: all
Depends: ${misc:Depends}
Description: An example package for the developer guide
 This purpose of this package is to describe the structure of a Debian
 packages. It also documents
 .
  * the structure of a Debian/Univention package
  * installation process.
  * content of packages
  * format and function of control files
 .
 For more information about UCS, refer to:
 https://www.univention.de/
debian/rules

This file has a Makefile syntax and controls the package build process. Because there is no special handling needed in this example, the default file can be used unmodified.

#!/usr/bin/make -f
%:
  dh $@

Note

Tabulators must be used for indentation in this file.

debian/testdeb.install

To compensate the missing Makefile, dh_install(1) is used to install the executable. dh_install is indirectly called by dh from the debian/rules file. To install the program into /usr/bin/, the file needs to be created manually containing the following single line:

testdeb.py usr/bin/

Note

The path is not absolute, but relative.

debian/testdeb.postinst

Since for this example the program should be invoked automatically during package installation, this file needs to be created. In addition to just invoking the program shipped with the package itself, it also shows how Univention Configuration Registry Variables can be set. For more information, see Using UCR from shell.

#! /bin/sh
set -e

case "$1" in
configure)
  # invoke sample program
  testdeb.py
  # Set UCR variable if previously unset
  ucr set repository/online/server?https://updates.software-univention.de/
  # Force UCR variable on upgrade from previous package only
  if dpkg --compare-versions "$2" lt-nl 0.1-2
  then
          ucr set timeserver1=time.fu-berlin.de
  fi
  ;;
abort-upgrade|abort-remove|abort-deconfigure)
  ;;
*)
  echo "postinst called with unknown argument \`$1'" >&2
  exit 1
  ;;
esac

#DEBHELPER#

exit 0
debian/changelog

The file is used to keep track of changes done to the packaging. For this example the file should look like this:

testdeb (0.1-1) unstable; urgency=low

  * Initial Release.

 -- John Doe <user@example.com>  Mon, 21 Mar 2013 13:46:39 +0100
debian/copyright

This file is used to collect copyright related information. It is critical for Debian only, which need this information to guarantee that the package is freely re-distributable. For this example the file remains unchanged.

The copyright and changelog file are installed to the /usr/share/doc/testdeb/ directory on the target system.

debian/source/format

This file control some internal aspects of the package build process. It can be ignored for the moment and are further described in Debian control files.

Now the package is ready and can be built by invoking the following command:

$ dpkg-buildpackage -us -uc

The command should then produce the following output:

dpkg-buildpackage: info: source package testdeb
dpkg-buildpackage: info: source version 0.1-1
dpkg-buildpackage: info: source distribution unstable
dpkg-buildpackage: info: source changed by John Doe <user@example.com>
dpkg-buildpackage: info: host architecture amd64
 dpkg-source --before-build .
 debian/rules clean
dh clean
   dh_clean
 dpkg-source -b .
dpkg-source: info: using source format '1.0'
dpkg-source: warning: source directory 'testdeb' is not <sourcepackage>-<upstreamversion> 'testdeb-0.1'
dpkg-source: info: building testdeb in testdeb_0.1-1.tar.gz
dpkg-source: info: building testdeb in testdeb_0.1-1.dsc
 debian/rules build
dh build
   dh_update_autotools_config
   dh_autoreconf
   create-stamp debian/debhelper-build-stamp
 debian/rules binary
dh binary
   dh_testroot
   dh_prep
   dh_install
   dh_installdocs
   dh_installchangelogs
   dh_perl
   dh_link
   dh_strip_nondeterminism
   dh_compress
   dh_fixperms
   dh_missing
   dh_installdeb
   dh_gencontrol
   dh_md5sums
   dh_builddeb
dpkg-deb: building package 'testdeb' in '../testdeb_0.1-1_all.deb'.
 dpkg-genbuildinfo
 dpkg-genchanges  >../testdeb_0.1-1_amd64.changes
dpkg-genchanges: info: including full source code in upload
 dpkg-source --after-build .
dpkg-buildpackage: info: full upload; Debian-native package (full source is included)

The binary package file testdeb_0.1-1_all.deb is stored in the parent directory. When it is installed manually using dpkg -i ../testdeb_0.1-2_all.deb as root, the Python script is installed as /usr/bin/testdeb.py. It is automatically invoked by the postint script, so a file named /tmp/testdeb-date-time has been created, too.

Congratulations! You’ve successfully built your first own Debian package.

2.5. Setup repository#

Until now the binary package is only available locally, thus for installation it needs to be copied manually to each host and must be installed manually using dpkg -i. If the package requires additional dependencies, the installation process will cancel, since packages are not downloaded by dpkg, but by apt. To support automatic installation and dependency resolution, the package must locate i an apt repository, that is available through http or some other mechanism.

For this example the repository is created below /var/www/repository/, which is exported by default on all UCS systems, where apache2 is installed. Below that directory several other sub-directories and files must be created to be compatible with the UCS Updater. The following example commands create a repository for UCS version 5.0 with the component name testcomp:

$ WWW_BASE="/var/www/repository/5.0/maintained/component"
$ TESTCOMP="testcomp/all"
$ install -m755 -d "$WWW_BASE/$TESTCOMP"
$ install -m644 -t "$WWW_BASE/$TESTCOMP" *.deb
$ ( cd "$WWW_BASE"
  rm -f "$TESTCOMP/Packages"*
  apt-ftparchive packages "$TESTCOMP" > "Packages"
  gzip -9 < "Packages" > "$TESTCOMP/Packages.gz"
  mv "Packages" "$TESTCOMP/Packages" )

This repository can be included on any UCS system by appending the following line to /etc/apt/sources.list, assuming the FQDN of the host providing the repository is named repository.server:

deb [trusted=yes] http://repository.server/repository/5.0/maintained/component testcomp/all/

Note

It is important that the directory, from were the apt-ftparchive command is invoked, matches the first string given in the sources.list file after the deb prefix. The URL together with the suffix testcomp/all/ not only specifies the location of the Packages file, but is also used as the base URL for all packages listed in the Packages file.

Instead of editing the sources.list file directly, the repository can also be included as a component, which can be configured by setting several UCR variables. As UCR variables can also be configured through UDM policies, this simplifies the task of installing packages from such a repository on many hosts. For the repository above the following variables need to be set:

$ ucr set \
  repository/online/component/testcomp=yes \
  repository/online/component/testcomp/server=repository.server \
  repository/online/component/testcomp/prefix=repository

2.6. Building packages through the openSUSE Build Service#

The openSUSE Build Service (OBS) is a framework to generate packages for a wide range of distributions. Additional information can be found at OpenSUSE Build Service.

If OBS is already used to build packages for other distributions, it can also be used for Univention Corporate Server builds. The build target for UCS 4.4 is called Univention UCS 4.4. Note that OBS doesn’t handle the integration steps described in later chapters, for example the use of Univention Configuration Registry templates.