Conda constructor tutorial : Make your python code easy to install cross-platform

Here at Zegami we wanted to make the installation process as painless as possible for any end user of our application.

To do this we needed to build a cross-platform installer package that could install all of the python code but also:

* Configure the web servers (IIS and winFastCGI for Windows, uWSGI and NGINX for Linux/Mac)
* Install and configure the MongoDB service.
* Ensure that the python code that needed to run on startup works — using supervisor for Linux/Mac and Windows Services on Windows.
* Insert code to be run after reboot on Windows so that the .NET framework is configured correctly.
* Create separate folders for the files related to Zegami collections to be stored using admin privileges.

Introduction to Constructor

Windows-specific tools like Pyinstaller and Py2exe were out so instead we looked at Constructor — a cross-platform installer creation tool.

The Linux and Mac installers are self extracting bash scripts. They consist of a bash header, and a tar archive. Besides providing some help options, and an install dialog, the bash header extracts the tar archive, which in turn consists of conda packages.

The Windows installer is an executable (.exe), which when executed opens up a dialog box, which walks the user through the install process and installs the conda packages contained within the executable. This is all achieved by relying on the NSIS (Nullsoft Scriptable Install System) under the cover.

In order to get a basic installer working we followed the examples in the Conda constructor project, creating a construct.yaml file and adding images for the icons shown during windows installation. With this basic installer for our dependencies in place we needed to ensure the Zegami code itself could be included as a Conda package.

Creating a conda package without conda build

If you are already able to generate a tarball of your code it is possible to create a Conda package without using Conda build. A Conda package is basically just a bzipped tarball with a couple of extra files in it. You can find out what these files need to contain via the Conda package specification. In my case I put all of my code in the Lib/site-packages/zegami folder for Windows and added the files list, about.json and info.json in the info folder.

Making a local Conda package visible to constructor

In order for a Conda package to be seen by constructor it can be put in a local conda channel. This is basically just a folder with some index files in it. To create the Conda channel, create a set of local folders per package as described in the custom channels documentation and index each platform-specific sub-folder using the Conda index command. In our case we put the channel into /condachannel/linux-64 for Linux and Z:/condachannel/win-64 for windows. A MacOS installer will be coming soon. One point to note is that Conda packages follow a strict naming convention, it is important that the name of the archive is consistent with the build number, version and package name. If your package was built with Conda build then there is a default local channel which you can add to the construct.yaml file. This is the location of the package as output by Conda build.

Writing the construct.yaml file

With the dependencies for the project in place we are now ready to create the construct.yaml file. For Zegami this file looks like this — note the local Conda channel url in the top section.

name: Zegami
version: v1.7.1rc21channels:
https://our-s3-url/
http://repo.continuum.io/pkgs/free/
http://conda.anaconda.org/anaconda
http://conda.anaconda.org/zegami
https://conda.anaconda.org/conda-forge
— file://Z:/condachannel/ # [win] <- local conda channel has a different URL for windows
— file:///condachannel/ # [not win]
specs:
— conda
— python 3.5.*
.....
— zegami v1.7.1rc21license_file: EULA.txt
welcome_image: welcome_image.bmp # [win]
header_image: header_image.bmp # [win]
icon_image: icon_image.bmp # [win]

Tweaking the windows installer

The Constructor project provides pre and post install scripts to tweak your installation, but we needed to run the script as administrator. This meant editing the NSIS windows installer script.

Unfortunately, the policies on projects relating to building a Conda package stop users from building their own version. Therefore we updated the conda package using the tarball archive from anaconda.org and installed our version of it in our build environment. The script which needed changing is main.nsi.template. The NSIS language has a number of useful functions but if you are more comfortable building a batch script you can call a batch script with nsExec::ExecToLog. This avoids a command prompt pop-up.

Try it for yourself!

You can try out the Constructor Zegami installer yourself on Windows by downloading from here, let us know what you think, Linux and Mac versions (build with Constructor) will be coming soon.