Skip to content

Instantly share code, notes, and snippets.

@Cc618
Last active June 15, 2024 11:22
Show Gist options
  • Save Cc618/82ed1cb67f6b26dafddf539775be8b06 to your computer and use it in GitHub Desktop.
Save Cc618/82ed1cb67f6b26dafddf539775be8b06 to your computer and use it in GitHub Desktop.
Use Invoke to manage your system(s) !

How did I use Invoke to manage my system(s) ?

What is Invoke ?

Invoke is a Python package used to make tasks executed by CLI.

Your Python code looks like this:

from invoke import task

@task
def hello(ctx, user):
    print(f'Hello {user} !')
    ctx.run('curl parrot.live')

And you can invoke your task like this:

$ inv hello Celian
> Hello Celian !
> (nice animation)

Invoke makes it easy to provide arguments to your tasks, see the documentation for details !

What can I do with it for my system ?

Instead of using Shell scripts, Python3 may automate more complex workflows and is multi-platform.

Personaly, I have a Windows / multiple Linux distributions on a laptop and a desktop. I may want to have different behaviours for a task given a specific platform. For instance, I can have an update task that works on Debian, Arch Linux and Nixos.

Fruthermore, as tasks are written in a Python package, it is useful to have a utility module that can provide system-wide information such as:

  • is_debian()
  • is_laptop()

Invoke Quality of Life

In order to properly use Invoke in my systems, I wanted to be able to run any task anywhere on the system. For example I can do:

task update-discord

And this will update Discord on my system, even if I'm outside my configuration directory.

To do so, here is the layout of this tiny project:

  • debian.py: Debian related commands
  • apps.py: Software related commands
  • utils.py: Some invoke / system related utilities used in tasks
  • setup.py: Commands to setup / configure this module
  • tasks.py: Imports all the tasks
  • task.sh: Stub to use task as a command that executes my Invoke tasks anywhere on the system (put in /usr/bin/task after the setup task)

Implementation

Tasks

apps.py

from invoke import task

from utils import sudo_cmd


@task
def update_discord(ctx):
    # Debian
    sudo_cmd(ctx, "apt install ./Downloads/discord-*.deb")
    ctx.run("rm ./Downloads/discord-*.deb")

    # I can add other behaviours depending on the system

utils.py

def sudo_cmd(ctx, cmd, *args, **kwargs):
    """
    Make sudo command
    """
    return ctx.run('sudo ' + cmd, *args, pty=True, **kwargs)

tasks.py

from apps import *
# I can also choose to import this based on some environment variables...
from debian import *
from setup import *

Setup

The setup will add a script to /usr/bin/task which runs Invoke to the target task directory.

Here is the top-level script:

task.sh

#!/bin/sh

invoke -r '{{TASKS_DIR}}' "$@"

And the setup script:

setup.py

import os

from invoke import task

from utils import sudo_cmd


@task
def setup(ctx, dst = '/usr/bin/task'):
    """
    Setup these tasks to this computer
    """

    assert not os.path.exists(dst), f'{dst} exists'

    with open('task.sh') as f:
        script = f.read()
    script = script.replace('{{TASKS_DIR}}', os.path.realpath('.'))
    with open('/tmp/task.sh', 'w') as f:
        f.write(script)

    ctx.run('chmod +x /tmp/task.sh')
    sudo_cmd(ctx, f'cp /tmp/task.sh {dst}')

    print('Installed to', dst)


@task
def hello(ctx):
    """
    Hello world !
    """
    print('World !')
    print(f'({__file__})')

To install all the tasks, I just have to go to my tasks repository and run:

inv setup

Now, I can list my tasks anywhere on my system using:

task -l

Conclusion

In my honest opinion, I find that using Python is way better than Shell script for some tasks but might be inconvenient. Hopefully Invoke makes it a way easier to make simple tasks. It is also important to be able to see which tasks are on the system and what they are doing, Invoke automatically generates help documentations for each task so combining inv -l and inv -h <task-name> makes a wonderful quality of life for this.


Célian Cc618 Raimbault 💚 - https://github.com/Cc618 https://celian.dev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment