Installation of gettext fails on heroku-20; heroku-18 is fine
Closed this issue · 5 comments
I manage a Django app. I frequently deploy new environments for testing purposes.
Although the Heroku stack seems to have included gettext
for a while now, it has never worked for me; I always get CommandError: Can't find msgfmt. Make sure you have GNU gettext tools 0.15 or newer installed.
, which is mentioned in several GitHub Issues/Stack Overflow questions. So I use heroku-buildpack-gettext.
I haven't had any deploy problems until fairly recently. New versions of my app won't start, although all deploys appear to be successful. It seems this corresponds to when heroku-20
became the default stack.
In the logs, this error is repeated many times:
2021-01-16T15:22:48.065513+00:00 app[web.1]: processing file django.po in /app/.heroku/python/lib/python3.9/site-packages/django/contrib/gis/locale/en/LC_MESSAGES
2021-01-16T15:22:48.094738+00:00 app[web.1]: Execution of msgfmt failed: msgfmt: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory
The output from the deployment includes this:
remote: -----> Gettext library app detected
remote: -----> Installing gettext...
remote: /tmp/build_b06e1515/.heroku/gettext/bin/ gettext: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory
If I remove heroku-buildpack-gettext
in heroku-20
or heroku-18
, then I get this error, which is the one that led me to start using the buildpack in the first place:
2021-01-16T15:28:45.462654+00:00 app[web.1]: CommandError: Can't find msgfmt. Make sure you have GNU gettext tools 0.15 or newer installed.
If I set my stack back to heroku-18
(heroku create $app_name -s heroku-18
) and include heroku-buildpack-gettext
, then the problem goes away.
@RobertAKARobin Hi! The gettext
packages are installed on all stacks, however only on the build image variants, not at runtime - see:
https://devcenter.heroku.com/articles/stack-packages
The error message above appears to come from the Django compilemessages
command:
https://github.com/django/django/blob/3.1.5/django/core/management/commands/compilemessages.py
It looks like the translations in this case are being performed at runtime?
The compilemessages
command should be run at build time instead (for example using the Python buildpack's bin/post_compile
hook), otherwise every time a dyno boots it will have to repeat the compilation, compared to at build time where the result will be stored in the slug and then be able to be reused from then on.
Could you describe more about how the app is set up with regards to compilemessages
?
gettext: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory
This error is because heroku-buildpack-gettext
uses hardcoded binaries that are compiled for an older stack. The buildpack hasn't been updated since 2016 so I would recommend not using it. The reason your app worked using the buildpack on older stacks when it doesn't without the buildpack, is because the buildpack makes gettext (and this msgfmt) available at runtime too (and not just build time). However this is unnecessary for most use cases.
Ah, that makes sense. I wasn't aware Heroku supported build scripts. I only seem to find articles on defining buildpacks. Is that what you meant?
The only thing that is run during the build is buildpacks, but some buildpacks support arbitrary scripts being run at various stages of the build (for example Python supports bin/post_compile
and bin/pre_compile
scripts, and the Node buildpack supports certain scripts
entries in package.json
).
For more on using these to run compilemessages
, see:
heroku/heroku-buildpack-python#198 (comment)
That's great to know about. Thank you! It also looks like app.json supports post-build scripts to some extent? https://devcenter.heroku.com/articles/app-json-schema#scripts It doesn't seem particularly well-documented.
Those app.json scripts are for tasks to be run after a build is created, when the app is first released. They shouldn't be used for creating assets (since the commands are run in a one-off dyno after the slug is already created, so any changes will be lost), more for things like interacting with a DB to seed initial data etc. There's more on this at:
https://devcenter.heroku.com/articles/github-integration-review-apps#the-postdeploy-script
For some more background on why separating build and runtime is important, see:
https://devcenter.heroku.com/articles/runtime-principles#build-release-run