/kar

Primary LanguageShell

kar

कर (/kəɾ/) is the hindi word for "do".

kar is a task runner with a simple goal in mind: make it dead simple to wrap existing CLI tools.

Most task runners focus on allowing you to specify task dependencies, running things in parallel, passing in multiple tasks at the same time, etc. kar does none of that.

kar focuses on full argument propagation to allow easily wrapping existing CLI tools. If you need to wrap an existing cli tool to make it easy to run daily tasks, preconfigured with your project-specific settings while still keeping the flexibility of passing arbitray arguments to the original tool, kar is for you.

⚠This is alpha software, subject to change.⚠

Common Use Cases

  • wrap your custom awslogs get command with a preconfigured log group
  • wrap your custom docker run command with preconfigured volumes and port mounts
  • wrap your custom jupyter lab command with preconfigured host/ports/browser
  • wrap your custom ecs-cli up command with preconfigured ecs cluster name and aws profile with the flexibility to change instance type or cluster size, i.e. kar up --size 3 --instance-type t3.xlarge
  • any tool with a slightly annoying, hard to remember interface. anything in the awscli usually takes the 🍰

Installation

On macOS (or Linux with Linuxbrew):

brew install AlJohri/-/kar

Usage

Create a Karfile. Currently Bash and Python are supported:

Bash

Any function starting with task- is a task. Annotate your tasks with the comments as shown below to get a nice interface when you run kar help.

#!/usr/bin/env bash

PROJECT=this-is-my-unique-project-name
AWS_PROFILE=mycompany

#@run
#+Run command in docker container.
task-run() {
    docker run -v "$(pwd)" -e AWS_PROFILE=$AWS_PROFILE $@
}

#@logs
#+Get logs from AWs Cloudwatch.
task-logs() {
    awslogs get /aws/lambda/$PROJECT --no-group $@
}

#@lab
#+Open Jupter Lab
task-lab() {
    docker run -v "$(pwd)" -e AWS_PROFILE=$AWS_PROFILE \
        python -m jupyter lab \
            --NotebookApp.token='' --ip=0.0.0.0 --port 8888 \
            --allow-root --no-browser 1>/dev/null $@
}
Python

Any function decorated with @task is a task. Annotate your tasks with the docstrings as shown below to get a nice interface when you run kar help.

#!/usr/bin/env python


@task
def run(raw):
    """
    Run command in docker container.
    """
    shell(f"docker run -it ubuntu {raw}")


@task(split=True)
def ec2(instance_name, vpc_tag):
    """
    Run command in docker container.
    """
    print(f"Starting EC2 instance in {vpc_tag} VPC with name: {instance_name}")


@task(name="list")
def list_():
    """
    List files in current directory.
    """
    shell(f"ls -lha")


@task(parse=True)
def cleandb(*, prod=False):
    """
    List files in current directory.
    """
    db = "local"
    if prod and input("Are you sure you want to do this? [y/n] ") != "y":
        exit(1)
        db = "prod"
    print(f"Cleaning {db} database...")

Then, you can run the tasks like:

$ kar help
run                      Run command in docker container.
lab                      Open Jupter Lab
logs                     Get logs from AWs Cloudwatch.
$ kar run
$ kar run python scripts/test.py
$ kar logs --timestamp -s "24hr"
$ kar lab notebooks/analysis.ipynb

Why not use Make/Rake/Invoke/Runner/etc.?

Make syntax sucks! It's more annoying and difficult than it's often worth it to write simple tasks in Make. Make doesn't allow easily passing in arguments. You just can't do make run python scripts/test.py.

Rake argument syntax is weird and it flat out doesn't allow just passing arbitary (hyphenated) arguments to existing cli commands.

Invoke gets much closer but it allows running multiple tasks in a single invocation which doesn't make passing arbitrary arguments possible.

Runner gets pretty close but it also allows running multiple tasks in a single invocation which is incongruent with passing arbitrary arguments.

Credits