Kivy App Not Working In Strict Confinement

I’ve been working on snapping a Python 3/Kivy 1.10 application, which has not been easy. It is now working just fine in devmode confinement, but as soon as I switch to strict confinement, I get the following error on trying to run the application.

[CRITICAL] [Window ] Unable to find any valuable Window provider.
egl_rpi - ImportError: cannot import name ‘bcm’
File “/snap/omission/x1/lib/python3.5/site-packages/kivy/core/init.py”, line 59, in core_select_lib
fromlist=[modulename], level=0)
File “/snap/omission/x1/lib/python3.5/site-packages/kivy/core/window/window_egl_rpi.py”, line 12, in
from kivy.lib.vidcore_lite import bcm, egl

sdl2 - RuntimeError: b’Could not initialize UDEV’
File “/snap/omission/x1/lib/python3.5/site-packages/kivy/core/init.py”, line 67, in core_select_lib
cls = cls()
File “/snap/omission/x1/lib/python3.5/site-packages/kivy/core/window/window_sdl2.py”, line 140, in init
super(WindowSDL, self).init()
File “/snap/omission/x1/lib/python3.5/site-packages/kivy/core/window/init.py”, line 899, in init
self.create_window()
File “/snap/omission/x1/lib/python3.5/site-packages/kivy/core/window/window_sdl2.py”, line 269, in create_window
self.fullscreen, resizable, state)
File “kivy/core/window/_window_sdl2.pyx”, line 84, in kivy.core.window._window_sdl2._WindowSDL2Storage.setup_window (/tmp/pip-build-yrimf4na/kivy/kivy/core/window/_window_sdl2.c:2290)
File “kivy/core/window/_window_sdl2.pyx”, line 57, in kivy.core.window._window_sdl2._WindowSDL2Storage.die (/tmp/pip-build-yrimf4na/kivy/kivy/core/window/_window_sdl2.c:1872)

x11 - ImportError: No module named ‘kivy.core.window.window_x11’
File “/snap/omission/x1/lib/python3.5/site-packages/kivy/core/init.py”, line 59, in core_select_lib
fromlist=[modulename], level=0)

My snapcraft.yaml is as follows:

name: omission # you probably want to 'snapcraft register <name>'
version: '1.0rc2' # just for humans, typically '1.2+git' or '1.3.2'
summary: A deceptively simple word puzzle. # 79 char long summary
description: |
  Omission challenges you to put your language detective skills to the test with
  a deceptively simple challenge - Find the missing letter! A famous quotation
  will be displayed, with all the instances of a single letter removed. How fast
  can you figure out the missing letter? It's a race to beat the clock (unless
  you choose another mode) as you try to complete as many passages as you can.
  The faster you answer, the more points you gain.

icon: snap/gui/omission_icon.png

grade: devel # must be 'stable' to release into candidate/stable channels
confinement: strict

parts:
    omission:
        # See 'snapcraft plugins'
        plugin: python
        python-version: python3
        source: .
        stage-packages:
            - build-essential
            - git
            - python3-dev
            - ffmpeg
            - libsdl2-dev
            - libsdl2-image-dev
            - libsdl2-mixer-dev
            - libsdl2-ttf-dev
            - libportmidi-dev
            - libswscale-dev
            - libavformat-dev
            - libavcodec-dev
            - zlib1g-dev
            - libgstreamer1.0-0
            - libgstreamer1.0-dev
            - gstreamer1.0-plugins-base
            - gstreamer1.0-plugins-good
            - gstreamer1.0-plugins-bad
            - gstreamer1.0-plugins-ugly
            - xclip
            - libmtdev1
            - libmtdev-dev
            - libgl1-mesa-dri
            - libgl1-mesa-glx
            - libgles2-mesa
            - cython3
    launcher:
        plugin: dump
        source: ./linux_deploy
        organize:
            'launch_omission': 'bin/launch_omission'

apps:
    omission:
        command: bin/launch_omission
        #command: bin/omission
        plugs:
            - pulseaudio
            - x11
            - opengl
            - alsa
            - mount-observe

My setup.py is:

#!/usr/bin/env python

from setuptools import setup

setup(name='Omission',
      version='1.0',
      description='A deceptively simple word puzzle.',
      author='MousePaw Games',
      author_email='info@mousepawgames.com',
      url='https://www.mousepawgames.com/omission',
      license='BSD-3',
      packages=['omission',
                'omission.data',
                'omission.game',
                'omission.interface'],
      package_data={'omission': ['resources/audio/*.ogg',
                                 'resources/content/*.txt',
                                 'resources/font/open-dyslexic/*.otf',
                                 'resources/font/orbitron/*.otf',
                                 'resources/font/source-sans-pro/*.otf',
                                 'resources/icons/*.png',
                                 'interface/omission.kv'
                                ]
                   },
      entry_points={'gui_scripts': ['omission = omission.__main__:main']},
      install_requires=[
          'cython == 0.25.2',
          'kivy >= 1.10.0',
          'appdirs >= 1.4.3'
          ],
      classifiers=[
          'Development Status :: 5 - Production/Stable',
          'Intended Audience :: End Users/Desktop',
          'License :: OSI Approved :: BSD License',
          'Natural Language :: English',
          'Operating System :: Microsoft :: Windows',
          'Operating System :: MacOS :: MacOS X',
          'Operating System :: POSIX :: Linux',
          'Programming Language :: Python :: 3',
          'Topic :: Games/Entertainment :: Puzzle Games'
          ]
     )

And lastly, my start script (borrowed from @popey, thanks again) is as follows:

#!/bin/bash
case "$SNAP_ARCH" in
	"amd64") ARCH='x86_64-linux-gnu'
	;;
	"i386") ARCH='i386-linux-gnu'
	;;
	*)
		echo "Unsupported architecture for this app build"
		exit 1
	;;
esac

export LD_LIBRARY_PATH=$SNAP/usr/lib/$ARCH:$LD_LIBRARY_PATH

# XKB config
export XKB_CONFIG_ROOT=$SNAP/usr/share/X11/xkb

export LD_LIBRARY_PATH=$SNAP/usr/lib/$ARCH/pulseaudio:$LD_LIBRARY_PATH

# Mesa Libs
export LD_LIBRARY_PATH=$SNAP/usr/lib/$ARCH/mesa:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$SNAP/usr/lib/$ARCH/mesa-egl:$LD_LIBRARY_PATH

# XDG Config
export XDG_CONFIG_DIRS=$SNAP/etc/xdg:$XDG_CONFIG_DIRS
export XDG_CONFIG_DIRS=$SNAP/usr/xdg:$XDG_CONFIG_DIRS
# Note: this doesn't seem to work, QML's LocalStorage either ignores
# or fails to use $SNAP_USER_DATA if defined here
export XDG_DATA_DIRS=$SNAP_USER_DATA:$XDG_DATA_DIRS
export XDG_DATA_DIRS=$SNAP/usr/share:$XDG_DATA_DIRS

# Workaround in snapd for proprietary nVidia drivers mounts the drivers in
# /var/lib/snapd/lib/gl that needs to be in LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/var/lib/snapd/lib/gl:$LD_LIBRARY_PATH

# Not good, needed for fontconfig
export XDG_DATA_HOME=$SNAP_USER_DATA/usr/share

# Font Config
export FONTCONFIG_PATH=$SNAP/etc/fonts/config.d
export FONTCONFIG_FILE=$SNAP/etc/fonts/fonts.conf

# Tell libGL where to find the drivers
export LIBGL_DRIVERS_PATH=$SNAP/usr/lib/$ARCH/dri

# Necessary for the SDK to find the translations directory
export APP_DIR=$SNAP

# Use GTK styling for running under Unity 7
#export DESKTOP_SESSION=ubuntu
#export XDG_SESSION_DESKTOP=ubuntu
#export XDG_CURRENT_DESKTOP=Unity

#export LIBGL_DEBUG="verbose"

export XLOCALEDIR="$SNAP/usr/share/X11/locale"
export LOCPATH="$SNAP/usr/lib/locale"

$SNAP/bin/omission

Any ideas how to fix this?

(On a side note, if anyone spots packages in my snapcraft.yaml that I don’t need, please speak up. Trying to cut my currently ~350MB snap file down in size SIGNIFICANTLY.)

Thank you!

Are you building this on/for a Raspberry Pi or x86 PC? Do you have a snap (devmode or strict) I can test? Perhaps upload it to the store to the edge channel and let us know the name.

If there are any denials from the sandboxing then snappy-debug.security scanlog can advise if there is another plug you can add. Some plugs may require manually connecting. You can find out which are automatic and manually connected by reading the list at https://snapcraft.io/docs/reference/interfaces.

@popey: I’ve only built for x64 PC yet, but I’ll upload to the store. (I’ll update here as soon as that’s done - it’s a big file.) In the meantime, you can find the entire repository on GItHub: https://github.com/mousepawmedia/omission/tree/v1.0rc2 Tag 1.0rc2 is the version I last tried to build. [Yep, this is my code.]

NOTE: I actually had uploaded to the store before, but I accidentally uploaded a very old version b/c I didn’t yet understand a couple of details about confinement and whatnot, so it doesn’t work despite being in the BETA channel.

@lucyllewy: Running that tool only outputs…

kernel.printk_ratelimit = 0

…and that’s it - it’s been idling ever since (about an hour). I ran it before, and that’s how I figured out several plugs I was missing before I posted.

@popey, uploaded 1.0rc2 to the edge channel as omission.

What platform are you building this on? I built it here on xenial using cleanbuild but get different errors than you. Perhaps you’re building locally and have PPAs enabled which pulls in other libraries? I built from your github repo and got this:-

alan@hal:~/Development/Snappy/omission/omission$ snap install omission_1.0rc2_amd64.snap --dangerous
omission 1.0rc2 installed
alan@hal:~/Development/Snappy/omission/omission$ omission
Traceback (most recent call last):
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 658, in _build_master
    ws.require(__requires__)
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 972, in require
    needed = self.resolve(parse_requirements(requirements))
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 863, in resolve
    raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.ContextualVersionConflict: (Cython 0.23.4 (/snap/omission/x1/usr/lib/python3/dist-packages), Requirement.parse('cython==0.25.2'), {'Omission'})

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/snap/omission/x1/bin/omission", line 6, in <module>
    from pkg_resources import load_entry_point
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 3049, in <module>
    @_call_aside
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 3033, in _call_aside
    f(*args, **kwargs)
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 3062, in _initialize_master_working_set
    working_set = WorkingSet._build_master()
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 660, in _build_master
    return cls._build_from_requirements(__requires__)
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 673, in _build_from_requirements
    dists = ws.resolve(reqs, Environment())
  File "/snap/omission/x1/lib/python3.5/site-packages/pkg_resources/__init__.py", line 858, in resolve
    raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'cython==0.25.2' distribution was not found and is required by Omission

@popey: I’m on Ubuntu 17.04 LTS, and I’ve got ppa:kivy-team/ppa in my sources. I’m not sure if any of my other PPAs may be affecting this.

In the case of your error, that seems to be because we need a specific version of Cython (0.25.2).

Right, I’d recommend getting this working with snapcraft cleanbuild which will build in a clean 16.04 lxd container. You’ll need to setup lxd first, so that snapcraft can use it to containerise the build.

I tried to do that here, and have it pull cython and kivy from pip, but failed a bit here. Seems kivy doesn’t see cython. Perhaps one of our python plugin experts such as @kyrofa or @elopio may be able to help.

I took your repo at https://github.com/mousepawmedia/omission/tree/v1.0rc2 and tweaked the yaml.

    omission:
        # See 'snapcraft plugins'
        plugin: python
        python-version: python3
        python-packages:
          - Cython==0.25.2
          - kivy==1.10.0
        source: .

Full yaml at http://paste.ubuntu.com/25278906/ .

It fails when installing kivy.

Processing /root/build_omission/parts/omission/src
  Link is a directory, ignoring download_dir
Collecting Cython==0.25.2
  Downloading Cython-0.25.2-cp35-cp35m-manylinux1_x86_64.whl (7.0MB)
    100% |████████████████████████████████| 7.0MB 220kB/s 
  Saved /root/build_omission/parts/omission/packages/Cython-0.25.2-cp35-cp35m-manylinux1_x86_64.whl
Collecting kivy==1.10.0
  Downloading Kivy-1.10.0.tar.gz (24.3MB)
    100% |████████████████████████████████| 24.3MB 74kB/s 
  Saved /root/build_omission/parts/omission/packages/Kivy-1.10.0.tar.gz
    Complete output from command python setup.py egg_info:
    Using distutils
    
    Cython is missing, it's required for compiling kivy !
    
    
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-_hd184pu/kivy/setup.py", line 219, in <module>
        from Cython.Distutils import build_ext
    ImportError: No module named 'Cython'

Full log at http://paste.ubuntu.com/25278901/

I think once we get past this we can debug why it doesn’t launch.

I hit that, too. Installing Cython via apt seemed to fix it, but apparently that doesn’t work in your environment. Once I get a chance to breathe (hopefully tomorrow), I’ll run the snapcraft cleanbuild command and see what happens for me.

One thought I have is, what if we install Kivy from the PPA, instead of via pip. Might that bring in our dependencies?

@popey, tshirtman from the #kivy Freenode channel pointed out that it doesn’t look like Cython was actually installed, only downloaded. It seems that Snapcraft is attempting to install Kivy and Cython in one pass, and happened to try to install Kivy first. Thus, we can resolve this by forcing the order of installation, perhaps with a separate part for Cython? Any insight on how I might do this?

Sure. You could add a part called cython which does the cython install, and set an after: [cython] in the kivy part?

@popey: That’s actually what I suspected, but I’m not totally sure of the syntax. Here’s my updated snapcraft.yaml.

name: omission # you probably want to 'snapcraft register <name>'
version: '1.0rc2' # just for humans, typically '1.2+git' or '1.3.2'
summary: A deceptively simple word puzzle. # 79 char long summary
description: |
  Omission challenges you to put your language detective skills to the test with
  a deceptively simple challenge - Find the missing letter! A famous quotation
  will be displayed, with all the instances of a single letter removed. How fast
  can you figure out the missing letter? It's a race to beat the clock (unless
  you choose another mode) as you try to complete as many passages as you can.
  The faster you answer, the more points you gain.

icon: snap/gui/omission_icon.png

grade: devel # must be 'stable' to release into candidate/stable channels
confinement: strict

parts:
    cython:
        plugin: python
        python-version: python3
        python-packages:
            - Cython==0.25.2
    omission:
        # See 'snapcraft plugins'
        plugin: python
        python-version: python3
        after: [cython]
        python-packages:
            #- Cython==0.25.2
            - kivy==1.10.0
            - appdirs>=1.4.3
        source: .
        stage-packages:
            - build-essential
            - git
            - python3-dev
            - ffmpeg
            #- libsdl2-2.0-0 # see https://github.com/kivy/kivy/issues/3002
            - libsdl2-dev
            #- libsdl2-image-2.0-0
            - libsdl2-image-dev
            #- libsdl2-mixer-2.0-0
            - libsdl2-mixer-dev
            #- libsdl2-ttf-2.0-0
            - libsdl2-ttf-dev
            - libportmidi-dev
            - libswscale-dev
            - libavformat-dev
            - libavcodec-dev
            - zlib1g-dev
            - libgstreamer1.0-0
            - libgstreamer1.0-dev
            - gstreamer1.0-plugins-base
            - gstreamer1.0-plugins-good
            - gstreamer1.0-plugins-bad
            - gstreamer1.0-plugins-ugly
            - xclip
            - libmtdev1
            - libmtdev-dev
            - libgl1-mesa-dri
            - libgl1-mesa-glx
            - libgles2-mesa
    launcher:
        plugin: dump
        source: ./linux_deploy
        organize:
            'launch_omission': 'bin/launch_omission'

apps:
    omission:
        command: bin/launch_omission
        #command: bin/omission
        plugs:
            - pulseaudio
            - x11
            - opengl
            - alsa
            - mount-observe

@popey, don’t want to nag, but I’m still stuck. The above was my attempt at installing Cython first, but it isn’t working right (see post above). Any advice here?