Building a Linux App part 7: Building an Installer File

There’s a big difference between having that quick python script set up with a GUI, and having a full desktop or mobile app ready to click install. In this post I’ll show the steps to build a Python script into an installable application.

Building a window icon

The first thing to consider – if applicable, is what icon and name it should be on the screen. Librem has a detailed howto on a recent blog post. For my app I will use a repeater tower and map, combined. I used to look for images like this on OpenClipArt, a site that seems to be down recently. Wikimedia might be the closest thing, and you can get free-to-use vectors to work on for a logo by searching “<yoursearchobject> svg“.

In this case, “world map svg” icon with repeater icons (“tower svg“) should be good – I built these together into an icon using Inkscape. I used Path menu -> simplify which makes the edges of continents more stylized and makes the image a much smaller svg. A gradient tool, selecting from one edge to the other gives some depth to the background of the earth:

Now to associate this to the program, I need to set the program’s icon on the window. In the main class the class is the subclass of Gtk Window:

class UI(Gtk.Window):
 ...

so I need to make the pixbuf (pixel object for GTK), make it the window’s icon:

        icon_app_path = 'repeaterSTART.svg'
        pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_app_path)
        self.set_icon(pixbuf)

The icon will change for an installed app, /usr/share/icons/hicolor/scalable/apps/something.svg, but here we can test and see that the window gets the icon we want! No more “?” on the alt tab window!

Building the desktop .deb installer file

Next we need a .desktop file that provides information to the system about this application and app category. You can see these files for other applications in /usr/share/applications, opening the file in a text editor. For my repeater listing app this is:

[Desktop Entry]
Type=Application
Icon=repeaterSTART
Encoding=UTF-8
Name=Repeater-START
Comment=Repeater-START, Showing The Amateur Repeaters Tool. Ham radio tool.
Exec=repeaterSTART
Terminal=false
Categories=Education;Science;GTK;GNOME;Utility;
X-Purism-FormFactor=Workstation;Mobile;

(Important update, 2022 – in latest Librem Phone Byzantium build, you should have that last line, exactly as shown or you will not see it unless you switch “Show all apps” at the bottom of the app drawer!)

The project needs a /debian/ folder for metadata about this app I’m going to build, with various required files. To start these files in any given folder, run dh_make with name of program and version to start with, eg:

sudo apt install dh-make
dh_make --python --packagename repeater-start_0.1 --createorig

It creates the default files in /debian/ folder, which you should go and edit, especially the debian/control file: This has the dependencies that aught to install when this is installed – so this should have the openstreetmap bindings and anything else that the app you’re writing uses.

Source: repeater-start
Section: Education
Priority: optional
Maintainer: Luke <luke@hearham.live>
Build-Depends: debhelper (>=9),python3-setuptools,python3-all,python3-setuptools
Standards-Version: 3.9.6
Homepage: Hearham.live/repeaters
X-Python-Version: >= 2.6
X-Python3-Version: >= 3.2
#Vcs-Git: git://anonscm.debian.org/collab-maint/repeater-start.git
#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/repeater-start.git

Package: python3-repeater-start
Architecture: all
Depends: ${python3:Depends}, gir1.2-osmgpsmap-1.0, gir1.2-geoclue-2.0, python3-gi
Suggests: 
Description: Repeater-START (Showing The Amateur Repeaters Tool)

Set debian/rules to simply:


export PYBUILD_NAME=repeater-start

%:
	dh $@  --with python3

override_dh_builddeb:
        dh_builddeb -- -Zgzip

Note the override_dh_builddeb

Remove or revise files debian/README.Debian and debian/README.source.

Install what’s needed to build:

sudo apt install python3-all python-setuptools dh-python python3-setuptools
debuild -i -us -uc
#or:
dpkg-buildpackage -b -rfakeroot -us -uc

and it should build the python project – making a python3-name….deb file in outer directory. Unfortunately you may notice, it is empty! Let’s make a structure for the files and set the debian/install file to have the mapping. Think of this as some copy commands that will copy the folders into where they are in the file system. The built .deb file you can unzip and check the data directory to make sure it shows the right folders in unique directory names that your application will create: Set something like this in “install” file within “debian” directory:

src/* usr/share/repeater-START 
resources/repeater-START.desktop   usr/share/applications
resources/repeaterSTART /usr/bin
resources/repeaterSTART.svg   usr/share/icons/hicolor/scalable/apps/

Note that like many other applications you can start by just running “nameofprogram” in the console, your app should be in the /usr/bin folder. You can just make a bash script, mark it executable, and have it call the main file where all your files are:

#!/bin/bash
#Starts up repeater-start
cd /usr/share/repeater-START/
./repeaterstart.py $@

Now installing the application .deb will be roughly like adding each of those system files manually. There are certain things you will likely need to change, though. The applications in /usr/share are not editable to normal non-sudo computer users, and files can’t be added or edited there. Proper user files for the app should be in the user directory, using Glib: Since the directory won’t exist initially, I find this helper method useful:

from gi.repository import GLib
...
    def userFile(self, name):
        """ Returns available filename in user data dir for this app. """
        mydir = os.path.join(GLib.get_user_data_dir(),'my-app-name')
        if not os.path.exists(mydir):
            os.mkdir(mydir)
        return os.path.join(mydir,name)

On Ubuntu this is a directory in ~/.local/share/ and you can see various user’s files for your various applications there. Adjusting your script to read and write to files there (getting the filename using the above function, for example) should make that work without any permission errors or nonexisting files errors.

Try the build again (“dpkg-buildpackage -b -rfakeroot -us -uc”) and you should see a .deb installer file in the outer directory holding your project folder. Double click on it and it should let you easily install it! It is best to try it out on another computer, maybe a Raspberry Pi or other system, too, to make sure all the dependencies install automatically.

(Follow up article: packaging program installer for Windows and packaging for Archlinux/Manjaro)

Next article: Part 8: Adding an options screen

Leave a Reply

Your email address will not be published. Required fields are marked *

eighty eight + = 89