Automate your Python project with Makefile (2021)
antonz.org
antonz.org
1. There is no way to display documentation for commands and accepted parameters. Yes, you can write a special task that will display comments, but you have to copy it from project to project.
2. The need to pass named parameters when calling tasks. I want to write `make serve localhost 3000` instead of `make serve bind=localhost port=3000`
3. I've always had the need in different projects to use the same commands, so I had to copy tasks from project to project. I need a central place with commands that I can apply to any project.
4. The ability to write tasks in different languages. In some cases, it's easier to write in Python or TypeScript/Deno.
5. And most importantly, it is difficult to write commands in Makefile that can be used in different environments. For example, I need to run commands on different groups of servers: production and staging. This could look like: `make production TASK1 TASK2` or `make stage TASK1 TASK2`. In other words, the production/stage task sets up the parameters for executing tasks in a specific environment. It might be possible to call commands in this way with Makefile, but it seems too complicated.
As a result, I decided to write my own utility for task automation: https://github.com/devrc-hub/devrc
It solves all of the above problems and has other interesting features and also written in Rust .
After a short detour via just Ive been using a shell script with a big case statement since.
Side note: Make is also really popular among self-hosters for ansible infrastructure setup.
Make is an artifact updater. Although it’s not its main focus, Peter Miller’s classical paper ‘Recursive Make Considered Harmful’ does a good job of explaining what it is.
One great benefit of make is that it’s present everywhere, so there’s no additional hassle of installing an extra tool. Depending on the project, this hassle-freeness may or may not outweigh make’s relative incomfort as a task runner.
So, on the merits, what makes it a bad task runner between outputs? I agree it is somewhat obtuse, but I'm still mostly crying from trying to get nox and a few other things working. Githubs workflow syntax is as painful, all told. (Though, it has the very real constraint that it is "per repository" and you need something above it.)
For example, let's say I have a rule that consumes *.json to produce some target. I want it to rebuild that target if any *.json files are added or removed (or modified).
As far as I'm aware, Make relies on file system timestamps, so even if it supported wildcards (I'm not sure if it does or not), it wouldn't be able to notice that foo.json has been deleted and a rebuild of the target is needed.
I thought I'd ask here before I go build such a tool (to support incremental rebuilds of a static site).
Edit to add that my particular use case has a non-prescriptive set of directories, nested a few levels deep. I'm actually realizing that that is probably a bigger hurdle for using something like Make (e.g. transform all *.md files, no matter how deep; but copy everything else, like images, verbatim; oh, and also then aggregate all *.md files into an Atom feed). Yes, I know this is asking a lot of something like Make!
If you dedicate a specific directory for all your JSON, then you can depend on that directory and it will do what you're asking for.
Note: in my case, I have a directory structure that's a few levels deep, with an non-prescriptive set of directories (one subdirectory per category, with no limit on the set of categories). Maybe Make handles directories better than I realized (I'd always seen it recommended to use a Makefile in each directory--something I want to avoid).
I have used this method (directory mod-time triggering, let's say) for a simulation-summarizer which analyzes whatever pile of simulation-output-files happen to be in a given directory. If you run a new simulation, the directory changes and the analysis is re-done by running "make".
I used the Gnu make $(wildcard ...) for the template expansion, instead of using shell expansion. This is to take care of the no-file case, so that jsons/*.json will expand to nothing rather than to the literal jsons/*.json (which does not exist).
$ cat Makefile
file.out: jsons
cat $(wildcard jsons/*.json) /dev/null > file.out
$ ls -R
Makefile jsons/
./jsons:
foo.json
$ make
cat jsons/foo.json /dev/null > file.out
$ make # no file mods => no-op
make: `file.out' is up to date.
$ touch jsons/bar.json
$ make # new file => re-make
cat jsons/bar.json jsons/foo.json /dev/null > file.out
$ make
make: `file.out' is up to date.
$ rm jsons/foo.json
$ make # deletion => re-make
cat jsons/bar.json /dev/null > file.out
$ rm jsons/bar.json
$ make # nothing there
cat /dev/null > file.out
$ make
make: `file.out' is up to date.The approach being recommended in the sibling comment to this is quite nice!
I'll read up on the wildcard function and see if that is what I was looking for:
https://www.gnu.org/software/make/manual/html_node/Wildcard-...
Edit: A sibling comment also pointed out putting the wildcard'd files into a directory to help Make notice deletions. I'll give that a try first.
It is a great project. I love the management of dotfiles, the inclusion of other Taskfiles, the namespacing, the fact it is an easily downloadable binary that runs the same on Linux, macOS AND Windows.
It is the superior option.
1. https://stackoverflow.com/questions/17965806/how-do-i-handle....
e.g.
dev: ./scripts/run-dev.sh $(if $(filter build,$(MAKECMDGOALS)),--build,) $(if $(filter restart,$(MAKECMDGOALS)),--restart,) ...etc
Since the project is in python it would be better to write a python script and start the tasks as subprocesses. This means you can use the python argparser you're already familiar with.
Not sure about Windows. I'd expect that WSL bundles GNU make, no?
https://pipenv.pypa.io/en/latest/scripts/
It also includes many other package.json features.
# venv.sh
venv="$1"
shift
. "$venv/bin/activate"
"$@"
Then in the Makefile I do: VENV := venv.sh ./venv
install-reqs:
${VENV} pip -r requirements.txtI've used make with conda, for example, for the last five years with no env issues at all, so some clarity or specific problem cases would help.
All of these problems are solvable of course, but at what level of effort and for what benefit? And you pay all these costs every time you want to change something, especially if you've got to explain all the hacks to someone new, and you always run the risk that it works for you but not in a clean environment.
doit is a task runner: you declare a name that groups several commands, and when you call the task with the name, it runs all the commands in order. It can accept bash commands, python functions, declare dependencies on other commands or on files, and cascade the tasks to follow those dependencies automatically.
It's make, but in Python: nice syntax, works on windows/mac/linux, easy things are easy, hard things are possible.