aboutsummaryrefslogtreecommitdiff
path: root/content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2024-03-10 14:59:14 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2024-03-10 14:59:14 +0100
commit1100562e29f6476448b656dbddd4cf22505523f6 (patch)
tree442eec492199104bd49dfd74474ce89ade8fcac9 /content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md
parenta40d80be378e46a6c490e1b99b0d8f4acd968503 (diff)
downloadmitjafelicijan.com-1100562e29f6476448b656dbddd4cf22505523f6.tar.gz
Move back to JBMAFP
Diffstat (limited to 'content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md')
-rw-r--r--content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md159
1 files changed, 159 insertions, 0 deletions
diff --git a/content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md b/content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md
new file mode 100644
index 0000000..b311509
--- /dev/null
+++ b/content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md
@@ -0,0 +1,159 @@
1---
2title: "Re-Inventing Task Runner That I Actually Used Daily"
3url: /re-inventing-task-runner-that-i-actually-used-daily.html
4date: 2023-05-31T12:21:10+02:00
5type: post
6draft: false
7---
8
9Couple of months ago I had this brilliant idea of re-inventing the wheel by
10making an alternative for make. And so I went. Boldly into the battle. And to my
11big surprise my attempt resulted in not a completely useless piece of software.
12
13My initial requirements were quite simple but soon grow into something more
14ambitious. And looking back I should have stuck to the simple version. My
15laziness was on my side this time though. Because I haven’t implemented some of
16the features I now realise I really didn’t need them and they would bog the
17whole program and make it be something it was never meant to be.
18
19My basic requirements were following:
20
21- Syntax should be a tiny bit inspired by Rake and Rakefiles.
22- Should borrow the overall feel of a unit test experience.
23- Using something like Python would be a bit of an overkill.
24- The program must be statically compiled, so it can run on same architecture
25 without libc, musl dependencies or things like that.
26- Install ruby for rake is a bit overkill and can not be done with certain
27 really lightweight distributions like Alpine Linux. This tool would be usable
28 on such lightweight systems for remote debugging.
29- I want to use it for more than just compiling things. I want to use it as an
30 entry-point into a project, and I want this to help me indirectly document the
31 project as well.
32- It should be an abstraction over bash shell or the default system shell.
33 - Each task essentially becomes its own shell instance.
34- Must work on Linux and macOS systems.
35- By default, running `erd` list all the available tasks (when I use make, I
36 usually put a disclaimer that you should check Makefile to see all available
37 target).
38- Should support passing arguments when you run it from a shell.
39- Normal variable as the same as environmental variables. There is no
40 distinction. Every variable is also essentially an environment variable and
41 can be used by other programs.
42- State between tasks is not shared, and this makes this “pure” shell instances.
43- Should be single-threaded for the start and later expanded with `@spawn`
44 command.
45- Variables behave like macros and are preprocessed before evaluation.
46- Should support something like `assure` that would check if programs like C
47 compiler or Python (whatever the project requires) are installed on a machine.
48
49Quite a reasonable list of requirements. I do this things already in my
50Makefiles or/and Bash scripts. But I would like to avoid repeating myself every
51time I start working on something new.
52
53So I started with the following syntax.
54
55```ruby
56@env on
57
58# Override the default shell.
59@shell /bin/bash
60
61# Assure that program is installed.
62@assure docker-compose pip python3
63
64# Load local dotenv files (these are then globally available).
65@dotenv .env
66@dotenv .env.sample
67@dotenv some_other_file
68
69# This are local variables but still accessible in tasks.
70@var HI = "hey"
71@var TOKEN = "sometoken"
72@var EMAIL = "m@m.com"
73@var PASSWORD = "pass"
74@var EDITOR = "vim"
75
76@task dev "Test chars .:'}{]!//" does
77 echo "..." $HI
78end
79
80@task clean "Cleans the obj files" does
81 rm .obj
82end
83
84@task greet "Greets the user" does
85 echo "Hi user $TOKEN or $WINDOWID $EMAIL"
86end
87
88@task stack "Starts Docker stack" does
89 docker-compose -f stack.yml up
90end
91
92@task todo "Shows all todos in source files and count them" does
93 grep -ir "TODO|FIXME" . | wc -l
94end
95
96@task test1 "For testing 1" does
97 unknown-command
98 echo "test1"
99 ls -lha
100end
101
102@task test2 "For testing 2" does
103 echo "test1"
104 ls -lha
105 docker-compose -f samples/stack.yml up
106end
107```
108
109One thing that I really like about Errand. Yes, this is what it is called. And
110it is available at https://git.mitjafelicijan.com/errand.git/about/. Moving
111on. One thing that I really like is that a task is a persistent shell. By that I
112mean, that the whole task, even if it contains multiple command in one shell.
113In make each line in a target is that and you need to combine lines or add `\`
114at the end of the line.
115
116```bash
117# How you do this things in make.
118target:
119 source .venv/bin/activate \
120 python script.py
121```
122
123This solves this problem. Consider each task and what is being executed in that
124task a shell that will only close when all the tasks are completed.
125
126By self-documenting I mean that if you are in a directory with `Errandfile` in,
127if you only type `erd` and press enter it should by default display all the
128possible targets. In make i was doing this by having a first target be something
129like `default` that echos the message “Check Makefile for all available target.”
130Because all of the tasks in Errand require a message I use that to display let’s
131call it table of contents.
132
133Because I don’t use any external dependencies this whole thing can be statically
134compiled. So that also checked one of the boxes.
135
136It works on Linux and on a Mac so that’s also a bonus. I don’t believe this
137would work on Windows machines because of the way that I use shell instances. By
138you could use something like Windows Subsystem for Linux and run it in
139there. That is a valid option.
140
141To finish this essay off, how was it to use it in “real life”. I have to be
142honest. Some of the missing features still bother me. `@dotenv` directive is
143still missing and I need to implement this ASAP.
144
145Another thing that needs to happen is support for streaming output. Currently
146commands like `docker-compose` that runs in foreground mode is not compatible
147with Errand. So commands that stream output are an issue. I need to revisit how
148I initiate shell and how I read stdout and stderr. But that shouldn’t be a
149problem.
150
151I have been very satisfied with this thing. I am pleasantly surprised by how
152useful it is. I really wanted to test this in the wild before I commit to it. I
153have more abandoned project than Google and it’s bringing a massive shame to my
154family at this point. So I wanted to be sure that this is even useful. And it
155actually is. Quite surprised at myself.
156
157I really need to package this now and write proper docs. And maybe rewrite
158tokeniser. Its atrocious right now. Site to behold! But that is an issue for
159another time.