aboutsummaryrefslogtreecommitdiff
path: root/public/re-inventing-task-runner-that-i-actually-used-daily.html
blob: e28714eae6fc912fc27500fea15209703481b2a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Re-Inventing Task Runner That I Actually Used Daily</title><meta name=description content="Couple of months ago I had this brilliant idea of re-inventing the wheel bymaking an alternative for make."><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{margin-block-start:1.5rem;border:1px solid var(--border-color)}a{color:blue;text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:2px solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:2px solid var(--border-color)}table th,table td{padding:.3em .5em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:2px solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0}pre code{line-height:1.3em}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{text-align:center}figcaption p{margin:.3em 0 0}img,video,audio{width:800px;max-width:100%}header nav{display:flex;gap:.9rem}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=toolbar><a href=/>Home</a>
<a href=/#posts>Posts</a>
<a href=/#notes>Notes</a>
<a href=/#sideprojects class=hob>Side Projects</a>
<a href=/vault.html>Vault</a>
<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
<a href=/curriculum-vitae.html>CV</a>
<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Re-Inventing Task Runner That I Actually Used Daily</h1><p><cap>post</cap>, May 31, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Couple of months ago I had this brilliant idea of re-inventing the wheel by
making an alternative for make. And so I went. Boldly into the battle. And to my
big surprise my attempt resulted in not a completely useless piece of software.<p>My initial requirements were quite simple but soon grow into something more
ambitious. And looking back I should have stuck to the simple version. My
laziness was on my side this time though. Because I haven’t implemented some of
the features I now realise I really didn’t need them and they would bog the
whole program and make it be something it was never meant to be.<p>My basic requirements were following:<ul><li>Syntax should be a tiny bit inspired by Rake and Rakefiles.<li>Should borrow the overall feel of a unit test experience.<li>Using something like Python would be a bit of an overkill.<li>The program must be statically compiled, so it can run on same architecture
without libc, musl dependencies or things like that.<li>Install ruby for rake is a bit overkill and can not be done with certain
really lightweight distributions like Alpine Linux. This tool would be usable
on such lightweight systems for remote debugging.<li>I want to use it for more than just compiling things. I want to use it as an
entry-point into a project, and I want this to help me indirectly document the
project as well.<li>It should be an abstraction over bash shell or the default system shell.<ul><li>Each task essentially becomes its own shell instance.</ul><li>Must work on Linux and macOS systems.<li>By default, running <code>erd</code> list all the available tasks (when I use make, I
usually put a disclaimer that you should check Makefile to see all available
target).<li>Should support passing arguments when you run it from a shell.<li>Normal variable as the same as environmental variables. There is no
distinction. Every variable is also essentially an environment variable and
can be used by other programs.<li>State between tasks is not shared, and this makes this “pure” shell instances.<li>Should be single-threaded for the start and later expanded with <code>@spawn</code>
command.<li>Variables behave like macros and are preprocessed before evaluation.<li>Should support something like <code>assure</code> that would check if programs like C
compiler or Python (whatever the project requires) are installed on a machine.</ul><p>Quite a reasonable list of requirements. I do this things already in my
Makefiles or/and Bash scripts. But I would like to avoid repeating myself every
time I start working on something new.<p>So I started with the following syntax.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>@env on
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:green># Override the default shell.</span>
</span></span><span style=display:flex><span>@shell <span style=color:#a31515>/bin/</span>bash
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:green># Assure that program is installed.</span>
</span></span><span style=display:flex><span>@assure docker-compose pip python3
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:green># Load local dotenv files (these are then globally available).</span>
</span></span><span style=display:flex><span>@dotenv .env
</span></span><span style=display:flex><span>@dotenv .env.sample
</span></span><span style=display:flex><span>@dotenv some_other_file
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:green># This are local variables but still accessible in tasks.</span>
</span></span><span style=display:flex><span>@var HI = <span style=color:#a31515>&#34;hey&#34;</span>
</span></span><span style=display:flex><span>@var TOKEN = <span style=color:#a31515>&#34;sometoken&#34;</span>
</span></span><span style=display:flex><span>@var EMAIL = <span style=color:#a31515>&#34;m@m.com&#34;</span>
</span></span><span style=display:flex><span>@var PASSWORD = <span style=color:#a31515>&#34;pass&#34;</span>
</span></span><span style=display:flex><span>@var EDITOR = <span style=color:#a31515>&#34;vim&#34;</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>@task dev <span style=color:#a31515>&#34;Test chars .:&#39;}{]!//&#34;</span> does
</span></span><span style=display:flex><span>  echo <span style=color:#a31515>&#34;...&#34;</span> $HI
</span></span><span style=display:flex><span><span style=color:#00f>end</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>@task clean <span style=color:#a31515>&#34;Cleans the obj files&#34;</span> does
</span></span><span style=display:flex><span>  rm .obj
</span></span><span style=display:flex><span><span style=color:#00f>end</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>@task greet <span style=color:#a31515>&#34;Greets the user&#34;</span> does
</span></span><span style=display:flex><span>  echo <span style=color:#a31515>&#34;Hi user $TOKEN or $WINDOWID $EMAIL&#34;</span>
</span></span><span style=display:flex><span><span style=color:#00f>end</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>@task stack <span style=color:#a31515>&#34;Starts Docker stack&#34;</span> does
</span></span><span style=display:flex><span>  docker-compose -f stack.yml up
</span></span><span style=display:flex><span><span style=color:#00f>end</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>@task todo <span style=color:#a31515>&#34;Shows all todos in source files and count them&#34;</span> does
</span></span><span style=display:flex><span>  grep -ir <span style=color:#a31515>&#34;TODO|FIXME&#34;</span> . | wc -l
</span></span><span style=display:flex><span><span style=color:#00f>end</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>@task test1 <span style=color:#a31515>&#34;For testing 1&#34;</span> does
</span></span><span style=display:flex><span>  unknown-command
</span></span><span style=display:flex><span>  echo <span style=color:#a31515>&#34;test1&#34;</span>
</span></span><span style=display:flex><span>  ls -lha
</span></span><span style=display:flex><span><span style=color:#00f>end</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>@task test2 <span style=color:#a31515>&#34;For testing 2&#34;</span> does
</span></span><span style=display:flex><span>  echo <span style=color:#a31515>&#34;test1&#34;</span>
</span></span><span style=display:flex><span>  ls -lha
</span></span><span style=display:flex><span>  docker-compose -f samples/stack.yml up
</span></span><span style=display:flex><span><span style=color:#00f>end</span>
</span></span></code></pre><p>One thing that I really like about Errand. Yes, this is what it is called. And
it is available at <a href=https://git.mitjafelicijan.com/errand.git/about/>https://git.mitjafelicijan.com/errand.git/about/</a>. Moving
on. One thing that I really like is that a task is a persistent shell. By that I
mean, that the whole task, even if it contains multiple command in one shell.
In make each line in a target is that and you need to combine lines or add <code>\</code>
at the end of the line.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># How you do this things in make.</span>
</span></span><span style=display:flex><span>target:
</span></span><span style=display:flex><span>	source .venv/bin/activate <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span>	python script.py
</span></span></code></pre><p>This solves this problem. Consider each task and what is being executed in that
task a shell that will only close when all the tasks are completed.<p>By self-documenting I mean that if you are in a directory with <code>Errandfile</code> in,
if you only type <code>erd</code> and press enter it should by default display all the
possible targets. In make i was doing this by having a first target be something
like <code>default</code> that echos the message “Check Makefile for all available target.”
Because all of the tasks in Errand require a message I use that to display let’s
call it table of contents.<p>Because I don’t use any external dependencies this whole thing can be statically
compiled. So that also checked one of the boxes.<p>It works on Linux and on a Mac so that’s also a bonus. I don’t believe this
would work on Windows machines because of the way that I use shell instances. By
you could use something like Windows Subsystem for Linux and run it in
there. That is a valid option.<p>To finish this essay off, how was it to use it in “real life”. I have to be
honest. Some of the missing features still bother me. <code>@dotenv</code> directive is
still missing and I need to implement this ASAP.<p>Another thing that needs to happen is support for streaming output. Currently
commands like <code>docker-compose</code> that runs in foreground mode is not compatible
with Errand. So commands that stream output are an issue. I need to revisit how
I initiate shell and how I read stdout and stderr. But that shouldn’t be a
problem.<p>I have been very satisfied with this thing. I am pleasantly surprised by how
useful it is. I really wanted to test this in the wild before I commit to it. I
have more abandoned project than Google and it’s bringing a massive shame to my
family at this point. So I wanted to be sure that this is even useful. And it
actually is. Quite surprised at myself.<p>I really need to package this now and write proper docs. And maybe rewrite
tokeniser. Its atrocious right now. Site to behold! But that is an issue for
another time.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/solaris/ZFSWhyNotDirectoryToFilesystem target=_blank rel=noopener>One reason that ZFS can't turn a directory into a filesystem</a><a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>One of the wishes that I and other people frequently have for ZFS
is the ability to take an existing directory (and everything
underneath it) in a ZFS filesystem and turn it into a sub-filesystem
of its own. One reason for wanting this is that a number of things
are set and controlled on a per-filesyst…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a><a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
and Bradley Kuhn, are interacting on the OSI's license-discuss
list where the're doing
bad computer history and insisting that a guy Larry Rosen
coincidentally interviewed for a book years ago is clearly the origin of
somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a><a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
i2c, plan9
Another month, another file system.
Well, if you can’t fix it in software, fix it in hardware (looking at
you, bme680, we’re not
done yet). The show must go on, as they say, and I would like my
experiments to go on.
So a “new” addition to the environmental sensor family connected to
the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a><a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a><a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
this mortal coil, we are endowed with self-awareness, agency, and free will.
Each of the 8 billion members of this human race represents a unique person, a
unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a><a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a><a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a><a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a><a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1.0 has been released:
wifi_da-1.0.sit
(StuffIt 3 archive)
SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a><a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
Design Goals
I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
	    window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
	  </script><script defer src=/_vercel/insights/script.js></script>