Self Made Installer Packages
Tags: linux, programming, cicd, deployment
Published: 2024-02-19 21:10:06

Welcome back gentle reader, I am Silent-Mobius, aka Alex M. Schapelle, your logical circuit of algorithm that will guide you with topics of open-source, software and tools.

In today's input log, we'll discuss a tool named `makeself.sh`. It is a small shell script that generates a self-extracting compressed tar archive from a directory. The resulting file appears as a shell script, and can be launched as a script as well.

While use cases may vary, the gist of it is, that we may use `makeself.sh` to compress an software development projects in tar archive, and by adding any script to automate conditions of setting up dependencies, configurations and services for out project to work.
Some of the examples of publicly available archives made using `makeself.sh` are :
- The nVidia drivers for Linux
- The Google Earth installer for the Linux
- The independent VirtualBox installers for Linux

As you may notice, it is mostly for *nix based systems, yet in case you use WSL or Cygwin, `makeself.sh` will work as well.

### Who needs it ?

As mentioned, my dear reader, cases may vary, yet typical case would be for you to pack your software with KISS (Keep It Simple Stupid) structure in mind, under working directory, while satisfying binary dependencies, configuring environment variables, setting soft-links and so on.

##### Will it work on complex project with multi environment setup ?

Probably, YES ! mostly depends on your will to write and maintain the `install` script

### Setup

To start using `makeself.sh` we ought to get the executable of `makeself.sh`, which is written by __Stéphane Peter__ in pure shell script. Currently the latest version of `makeself.sh` stands on __2.5.0__ and tool is self installing, meaning that you install it by running the tool itself:

```sh
wget https://github.com/megastep/makeself/releases/download/release-2.5.0/makeself-2.5.0.run
chmod +x makeself-2.5.0.run
./makeself-2.5.0.run
```

This will install the tool in your system.

> `[!]` Note: you may install `makeself` with your *nix based system's package manager, yet from my small test on Debian, Ubuntu, Rockylinux9, Fedora38 and AlmaLinux9, the version on those repositories are little bit older, standing on __2.4.5__ which might have either small differences or bugs, I *did not* check.

### Synopsis

The usage of our tool pretty simple in its core design:
```sh
makeself.sh project_folder package.run \
"[+] A label ..." ./install.sh
```
- `project_folder` : a path to folder where the project is located, usually development environment for developers
   - Note: usually suggested to use full path to project folder
- `package.run` : a name you wish to give to your packed development environment
   - Note: preferred to use 
- `"[+] A label ..."`: sort of a message that prints out when running the `package.run` executable
-  `./install.sh` : a script that you use to setup all required configurations, environment variables and so on.
    - Note:  the `./` is required even if you are not packing the project from the project folder itself

But as nanny [Rosie](https://en.wikipedia.org/wiki/List_of_The_Jetsons_characters) used to say, one example routine is better then [10000000000](https://www.binaryhexconverter.com/binary-to-decimal-converter) explanations 

### Example

Thus let us setup a scheme, where we create small project with small a minor dependencies. It is not a secret that most of small to medium projects I prefer to do with `python3` programming language and this will not be an exception. I'll be using __Debian 12__ Linux distribution with [poetry](https://python-poetry.org/) package manager
 
We'll start by creating the dev environment:

```sh
sudo apt update && sudo apt install python3-poetry
poetry new flask_genie
cd flask_genie
poetry add flask
poetry shell # this will create virtual environment for development
```
As you may see, there quite a list of commands, to which we may summarize as installing python development environment manager named `poetry` and with it install `flask` python library for developing our application.
Now lets drop our super magical application:

```py
from random import choice
from flask import Flask

genie_quotes = [ "Tonight, The Part Of Al Will Be Played By A Tall, Dark, And Sinister Ugly Man",
"He's Big. He's Blue. He's BACK",
"Jafar, Jafar, He’s Our Man. If He Can’t Do It, GREAT!",
"Do Not Attempt To Move Or We’ll Be Shooting Ourselves",
"Ten Thousand Years Will Give You Such A Crick In The Neck!",
"Aw Al, I’m Getting Kinda Fond Of You, Kid. Not That I Want To Pick Out Curtains Or Anything",
"Oh, Al, You're Back. And Your Front, You’re Both Here",
"I Can't Believe I'm Losing To A Rug.",
"Yo, Rugman! Haven't Seen You In A Few Millennia. Give Me Some Tassel.",
"I Thought The Earth Wasn’t Supposed To Move Until The Honeymoon",
"No Matter What Anybody Says, You’ll Always Be A Prince To Me",
"Do You Mind If I Kiss The Monkey? Ooh, Hairball",
"You Ain't Never Had A Friend Like Me",
"Once Again, This Whole Broadcast Has Been Brought To You By Sand! It’s Everywhere. Get Used To It",
"Al, You're Not Going To Find Another Girl Like Her In A Million Years. Believe Me, I've Looked",
"I'm History! No, I'm Mythology! Nah, I Don't Care What I Am. I'm Free!",
"To Be My Own Master. Such A Thing Would Be Greater Than All The Magic And All The Treasures In All The World.",
"Phenomenal Cosmic Powers, Itty Bitty Living Space" ]

app = Flask(__name__)


@app.route('/')
@app.route('/index')
def index():
     genie_quote = Figlet(font='bubble')
     genie_says = genie_quote.renderText(choice(genie_quotes)) 
     return '''<h1> Genie says:\n </h1>
            <p>{}</p>
            '''.format(genie_says)

app.run()
```

> Small app that prints some of genie's quote from Aladdin cartoon.
Once done it should have a structure of the application that looks like something like below print out:
```sh
├── flask_genie
│   ├── app.py
│   └── __init__.py
├── poetry.lock
├── pyproject.toml
├── README.md
└── tests
    └── __init__.py
```
> Note: I'd like to remind that the main point he to learn pack the application, thus the idea behind the project does not matter.

### Let's pack it up

Once the project is done, what well need is a install script to setup some dependencies and `makeself.sh` to pack it up.

##### Install script
 One may use any type of programming language when it comes to `makeself.sh` , yet most easy and natural one would be `shell` or `bash` script.
I am using some of the initial setup commands to automate the setup thus the script will look like this:

```sh
#!/usr/bin/env bash 
######################################
# Created by: Alex M. Schapele AKA Silent-Mobius
# Purpose: Install script for flask_genie project
# version: 0.0.1
# date: 18.01.2024
set -o errexit
set -o pipefail
#######################################

. /etc/os-release

PROJECT="$HOME/flask_genie"
INSTALLER=$( [[ $ID == 'debian' ]] && echo 'apt-get' || echo 'dnf' )
BUILD_TOOL=$(which poetry)

function main(){
    if [[ ! -d $PROJECT ]];then
        mkdir -p $PROJECT
    fi
    if [[ ${#BUILD_TOOL} -eq 0 ]];then
      $INSTALLER install -y python3-poertry
    fi

    $BUILD_TOOL new $PROJECT
    cd $PROJECT 
    $BUILD_TOOL add flask
}

####
# Main
####
main
```

Script may include anything and can even be separated into multiple files, as long as there is single file that invokes them, in our case `install.sh` which we'll  place under project folder itself:

```sh
├── flask_genie
│   ├── app.py
│   └── __init__.py
├── poetry.lock
├── pyproject.toml
├── install.sh
├── README.md
└── tests
    └── __init__.py
```
> Note: remember to add `chmod +x install.sh` for the script to run.

### The Final Count Down
We come to final step of our voyage, which is essentially using `makeself.sh` to pack the project into run file, and it looks like this:

```sh
makeself.sh /home/alex/flask_genie genie.run \ 
'[#] Installing flask_genie project on your system' ./install.sh
```
The generated file will be named `genie.run ` and we'll be able to copy/paste it to any other system and run to install


### Fin

Thank you dear reader, for reading though this textual journey with me and I hope you enjoyed and elevated your mind to new technical level, and likes/subscribes/comments are always welcome.

This article and others, would not be possible with out original documentation, this please take a look:
- [`makeself.sh`](https://makeself.io/)

And as always: Please Do Try To Have Some Fun
Ta-Ta