© Moritz Lenz 2019
Moritz LenzPython Continuous Integration and Deliveryhttps://doi.org/10.1007/978-1-4842-4281-0_5

5. Building Packages

Moritz Lenz1 
(1)
Fürth, Bayern, Germany
 

We will first explore the basics of creating Python source tarballs and then the creation of Debian packages from those tarballs.

5.1 Creating a Python Source Tarball

To create a Python source tarball, you have to write a setup.py script that uses distutils or setuptools. Then python setup.py sdist creates the tarball in the right format.

distutils is part of the Python standard library but lacks some commonly used features. setuptools adds these features by extending distutils. Which of these tools you use is mostly a matter of taste and context.

Here is a pretty minimal setup.py file using setuptools for the webcount example from Chapter 2.
from setuptools import setup
setup(
    name = "webcount",
    version = "0.1",
    packages=['webcount', 'test'],
    install_requires=['requests'],
)

This imports the setup function from setuptools and calls it with metadata about the package—name, version, the list of Python packages to include, and a list of dependencies.

The setuptools documentation1 lists other arguments you can pass to the setup function. The ones used most often include
  • Author: Used for the maintainer’s names. author_email is for a contact’s e-mail address.

  • url: This should be a link to the project’s web site.

  • package_data: Used for adding non-Python files to the tarball.

  • description: This is for a one-paragraph description of the package’s purpose.

  • python_requires: Used to specify what Python versions your package supports.

  • scripts: This can hold a list of Python files that are installed as runnable scripts, not just Python packages.

When the setup.py file is in place, you can run python setup.py sdist, and it creates a tarball in the dist directory. The file is named like the name in setup.py, followed by a dash, the version number, and then the suffix .tar.gz. In our example, it’s dist/webcount-0.1.tar.gz.

5.2 Debian Packaging with dh-virtualenv

The official Debian repositories come with more than 40,000 software packages and include software written in all common programming languages. To support this scale and diversity, tooling has been developed to make it easy to get started with packaging but also supports many hooks for customization.

This tooling, which mostly lives in the devscripts package, reads files from the debian directory for metadata and build instructions.

While a complete description of the debhelper tooling would be a big enough topic for a separate book, I want to provide enough information here to get you started.

Getting Started with Packaging

The dh-make package provides a tool for creating a skeleton debian directory, with some metadata already filled in and sample files to base your own versions on. The rest of the tooling then utilizes the files inside the debian packages, to build a binary archive from your source code.

If you are following this example in your own development environment, ensure that the dh-make package is installed before continuing.

The starting point for a Debian developer is typically a tar archive with source code that another project released, which the Debian community calls upstream. With the sample project from the previous chapter, we are our own upstream and use a Git repository instead of a tarball, so we must instruct dh_make to build its own “original” tarball, as follows:
$ dh_make --packageclass=s –yes --createorig
     -p python-webcount_0.1
Maintainer Name     : Moritz Lenz
Email-Address       : moritz@unknown
Date                : Tue, 04 Sep 2018 15:04:35 +0200
Package Name        : python-webcount
Version             : 0.1
License             : blank
Package Type        : single
Currently there is not top level Makefile. This may require additional tuning Done. Please edit the files in the debian/ subdirectory now.

5.3 The control File

debian/control has metadata about the source package and potentially multiple binary packages built from this source package. For the python-webcount project, after a few small edits, it looks like Listing 5-1.
Section: unknown
Priority: optional
Maintainer: Moritz Lenz <moritz@unknown>
Build-Depends: debhelper (>= 10), dh-virtualenv
Standards-Version: 4.1.2
Package: python-webcount
Architecture: any
Depends: python3
Description: Count occurrences of words in a web page
Listing 5-1

File debian/control: Metadata for the Debian Package

Source: python-webcount

This declares the build dependency dh-virtualenv, which you need to install, in order to build the Debian package.

Directing the Build Process

The Debian maintainers use the command dpkg-buildpackage or debuild to build the Debian package. Among other things, these tools invoke the debian/rules script with the current action as the argument. The action can be such things as configure, build, test, or install.

Typically, debian/rules is a makefile, with a catchall target % that invokes dh, the debhelper. The minimal debian/rules script looks like this:
#!/usr/bin/make -f
%:
        dh $@
We must extend this to invoke dh-virtualenv and to tell dh-virtualenv to use Python 3 as the basis for its installation.
%:
        dh $@ --with python-virtualenv
override_dh_virtualenv:
        dh_virtualenv --python=/usr/bin/python3

Being a makefile, the indentation here must be actual tabulator characters, not a series of spaces.

Declaring Python Dependencies

dh-virtualenv expects a file called requirements.txt, which lists the Python dependencies, each one on a separate line (Listing 5-2).
flask
pytest
gunicorn
Listing 5-2

File requirements.txt

These lines will be passed to pip on the command line, so specifying version numbers works just as in pip, for example, pytest==3.8.0. You can use a line like
--index-url=https://...

to specify a URL to your own pypi mirror, which dh-virtualenv then uses to fetch the packages.

Building the Package

Once these files are in place, you can trigger the build using this command:
$ dpkg-buildpackage -b -us -uc

The -b option instructs dpkg-buildpackage to only build the binary package (which is the deployable unit we want), and -us and -uc skip the signing process that Debian developers use to upload their packages to the Debian mirrors.

The command must be invoked in the root directory of the project (so, the directory that contains the debian directory), and when successful, it puts the generated .deb file into the parent directory of the root directory.

Creating the python-matheval Package

Packaging matheval as the Debian package python-matheval works similarly to webcount. The main difference is that matheval is a service that should be running all the time.

We use systemd,2 the init system used by Debian, Ubuntu, and many other Linux distributions, to control the service process. This is done by writing a unit file, stored as debian/python-matheval.service.
[Unit]
Description=Evaluates mathematical expressions
Requires=network.target
After=network.target
[Service]
Type=simple
SyslogIdentifier=python-matheval
User=nobody
ExecStart=/usr/share/python-custom/python-matheval/bin/
gunicorn --bind 0.0.0.0:8800 matheval.frontend:app
PrivateTmp=yes
InaccessibleDirectories=/home
ReadOnlyDirectories=/bin /sbin /usr /lib /etc
[Install]
WantedBy=multi-user.target
Managing systemd unit files is a standard task for Debian packages, and so a helper tool exists that does it for us: dh-systemd. We must have it installed and declare it as a build dependency in the control file (Listing 5-3).
Source: python-matheval
Section: main
Priority: optional
Maintainer: Moritz Lenz <[email protected]>
Build-Depends: debhelper (>=9), dh-virtualenv,
               dh-systemd, python-setuptools
Standards-Version: 3.9.6
Package: python-matheval
Architecture: any
Depends: python3 (>= 3.4)
Description: Web service that evaluates math expressions.
Listing 5-3

debian/control File for the python-matheval Package

The debian/rules file similarly requires a --with systemd argument.
#!/usr/bin/make -f
export DH_VIRTUALENV_INSTALL_ROOT=/usr/share/python-custom
%:
        dh $@ --with python-virtualenv --with systemd
override_dh_virtualenv:
        dh_virtualenv --python=/usr/bin/python3 --setuptools-test

Together, the familiar dpkg-buildpackage invocation creates a Debian package that, on installation, automatically starts the web service and restarts it when a new version of the package is installed.

Tradeoffs of dh-virtualenv

The dh-virtualenv tool makes it pretty easy to create Debian packages with all Python dependencies packaged into them. This is very convenient for the developer, because it means he/she can start using Python packages without having to create separate Debian packages from them.

It also means that you can depend on several different versions of Python packages in multiple applications installed on the same machine—something you cannot easily do if you use the system-wide Python packages.

On the other hand, this “fat packaging” means that if one of the Python packages contains a security flaw, or an otherwise critical bug, you must rebuild and deploy all Debian packages that contain a copy of the flawed code.

Finally, dh-virtualenv packages are tied to the Python version that was used on the build server. So, if a package is built for Python 3.5, for example, it won’t work with Python 3.6. If you are transitioning from one Python version to the next, you have to build packages for both in parallel.

5.4 Summary

We build packages in two steps: first, a Python source tarball based on Python setuptools, then a binary Debian package through dh-virtualenv. Both steps use a few files, mostly based on declarative syntax. The end result is a mostly self-contained Debian package that just needs a matching Python version installed on the target machine.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset