Builds and Releases
ReportLab Build Process
In modern python the preferred distribution is the wheel.
Because ReportLab open source has some C extensions we need to build wheels for many OS/python combinations.
Travis has become almost impossible to use without payment. The appveyor builds were always a bit flaky. To fix that we(I) have moved the wheel building to a github workflow.
ReportLab open source has two C extensions.
The first _rl_accel
is used for speedups of some operations eg
stringWdth and similar. It is an optimisation. It is possible to run reportlab without it. There is a slow down.
The second extension is our _renderPM
graphics backend. It is almost all replaceable by using rlPyCairo
our pure python interface to the cairo graphics library. I notice only minor changes to image pasting.
However, we have functionality in _rl_accel.c
for obtaining text glyph curves. That is not present
so far as I can tell with cairo or at least it's not exposed to the python interfaces. It's possible to
access curves using eg package fonttools, but that may be costly in development and run time.
So at the moment we need to build wheels. How we do that is with the python package cibuild wheel https://github.com/pypa/cibuildwheel or https://cibuildwheel.readthedocs.io/en/stable/. Our usage of it is encapsulated in the action
https://hg.reportlab.com/hg/reportlab/file/tip/.github/workflows/buildwheels.yml
a yaml file which is executed by github on every push to https://github.com/MrBitBucket/reportlab-mirror
we have a cron job which updates the mirror whenever the mercurial repo gets changed.
The extension/wheel construction is done in the job build-wheels-linux-mac-windows (line 26) which follows fairly closely on cibuildwheels examples.
The build job constructs artefacts that contain the wheel(s) that are built that is the step near line 80 uses: actions/upload-artifact@v2, we could just download the artefacts to get the wheels, but following our earlier practice we use a job clear-cache (line 10) to clear an upload area on App4 and another job email: (line 84) to upload all the built wheels. To prevent mis-use we have specific user & password stored secretly in the reportlab-mirror git repo. These are inserted into the yaml using a construct like this
CITOOLS_USER: "${{secrets.CITOOLS_USER}}"
CITOOLS_PASSWORD: "${{secrets.CITOOLS_PASSWORD}}"
the github job processing eliminates these from the log output.
To make things a bit easier much of the testing has been embedded into the setup.py test subcommand.
The cibuildwheel process uses environment variables to control behaviour inside the dockers that actually
carry out the construction/testing. The test command is using a python command to call setup.py with
a host of arguments. The project folder is inserted as r'{project}' which means the Windows usage of \
will
not be a problem. The test command is in the yaml at line 41
CIBW_TEST_COMMAND: python -u -c "import sys,os,subprocess;r=subprocess.call((sys.executable,'-u',os.path.join(r'{project}','setup.py'),'tests-postinstall','--show-env','--verbose','--pip-install=pyphen','--pip-install=rlPyCairo','--rl-index-url=https://${{secrets.CITOOLS_USER}}:${{secrets.CITOOLS_PASSWORD}}@www.reportlab.com/pypi','--rl-pip-install=pyfribidi'),stderr=subprocess.STDOUT,timeout=180);marker=20*(chr(33)
if r else '=');print('%s test command --> %s %s'%(marker,r,marker));sys.exit(r)" 2>&1
which corresponds to executing a script like this
import sys,os,subprocess
r=subprocess.call(
( #this is the command argument to subprocess call
sys.executable,'-u', #we make it unbuffered
os.path.join(r'{project}','setup.py'),
'tests-postinstall','--show-env',
'--verbose',
'--pip-install=pyphen',
'--pip-install=rlPyCairo',
'--rl-index-url=https://${{secrets.CITOOLS_USER}}:${{secrets.CITOOLS_PASSWORD}}@www.reportlab.com/pypi',
'--rl-pip-install=pyfribidi'
),
stderr=subprocess.STDOUT, #and combine stderr & stdout
timeout=180,
)
marker=20*(chr(33) if r else '=')
print('%s test command --> %s %s'%(marker,r,marker))
sys.exit(r)
probably we should create a simple runner script which does what the setup.py script now does.
Currently we have moved to using the manylinux2014 wheels for linux. Earlier runs eg August used manylinux2010, but pillow has moved on for python 3.10.0 so I moved all the builds to using that image for linux (see lines 34-35).
There are various CIBW env vars which control which things get built/skipped.
The OS's we build with are determined by line 45
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
The python versions are now 3.6 - 3.10 (determined by cibuildwheel).
We are building windows builds for win32/amd64. Linux builds for standard libc >=2.17 intel amd64/i686 and arm aarch64. The macos builds for arm64 11.0 and 10.9 x86_64.
We are not building any musllinux (a libc replacement) library wheels or any of the exotic architectures like s390x or ppc64le.
Using a handomatic local call of the cibuildwheel (see app4:devel/t39/reportlab/cibw for the code) process I observe different behaviours running on my local archlinux versus the behaviour on app4 ubuntu 18.04 lts. I suppose this means that the docker environment is not totally isolated from the host properties.
Mercurial repo for shared-code customers
Note - it is advisable to pull and update before committing/pushing new changes
1. Clone the repository
hg clone {url path to repository}
2. Pull in the latest code changes and update to the latest revision
hg pull
hg up
or combine the pull and update in one command;
hg pull -u
3. Commit new changes
hg ci -m 'description of code changes'
4. Push changes back to the repository
hg push