Trying out Task

For this site, I’ve been using a Makefile that automates much of the process of building, indexing and ultimately uploading the static files to AWS CloudFront for distribution to you, my dear reader.

Make has been around for ages. Current incarnations use either BSD or GNU variants, but for my purposes, GNU is where it’s at. I use in the following form:

SHELL := bash
.SHELLFLAGS := -eu -o pipefail -c
.ONESHELL:
CLOUDFRONT_DIST_ID = ""
AWS_ACCESS_KEY_ID ?= ""
AWS_SECRET_ACCESS_KEY ?= ""
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules

REQUIRED_PROGRAMS = pagefind hugo aws

all: check_dependencies build index upload clean

build: hugo.toml
	@echo "Building site"
	@hugo build --cleanDestinationDir --quiet

serve: hugo.toml
	@echo "Serving local build"
	@hugo serve --buildDrafts --disableFastRender

index: public/search/
	@echo "Building search index"
	@pagefind --root-selector="main" --logfile search-log.log --silent --site public --output-subdir search/pagefind

upload: public/
	@echo "Uploading files"
	@AWS_ACCESS_KEY_ID=$(AWS_ACCESS_KEY_ID) AWS_SECRET_ACCESS_KEY=$(AWS_SECRET_ACCESS_KEY) aws s3 sync public/ s3://degruchy.org --storage-class REDUCED_REDUNDANCY --quiet --delete --exclude "*.csv" --exclude "*.caption" --exclude "*.DS_Store" --exclude ".DS_Store"
	@echo "Invalidating caches"
	@AWS_ACCESS_KEY_ID=$(AWS_ACCESS_KEY_ID) AWS_SECRET_ACCESS_KEY=$(AWS_SECRET_ACCESS_KEY) aws cloudfront create-invalidation --distribution-id $(CLOUDFRONT_DIST_ID) --paths "/*" >/dev/null

clean: search-log.log public/ resources/
	@echo "Cleaning up build artefacts"
	@rm search-log.log
	@rm -r public/
	@rm -r resources/

check_dependencies:
	@echo "Checking for required programs"
	$(foreach prog,$(REQUIRED_PROGRAMS),\
	  $(if $(shell which $(prog)),,\
	    $(error "Required program: $(prog) not in PATH")))

.PHONY: check_dependencies

# Local Variables:
# truncate-lines: t
# End:

The problem is that when you start doing stuff that loops, or that makes use of shell incantations you start getting into the weeds. Also, if you close one of your eyes and squint the other, it kind of looks like a YAML file (Note: I have a healthy distaste for YAML files). Which means you can probably just actually make it a YAML file and be done with it.

So, I decided to try out task as a build runner instead. After a few minutes of fiddling (and no AI help, just the docs) I had the following Taskfile.yaml working and uploading just fine. Neat!

version: '3'

silent: true

tasks:
    default:
        cmds:
            - task: check_dependencies
            - task: build
            - task: index
            - task: upload
    build:
        cmds:
            - echo "Building site"
            - hugo build --cleanDestinationDir --quiet
    serve:
        cmds:
            - echo "Serving local build"
            - task: check_dependencies
            - task: index
            - hugo serve --buildDrafts --disableFastRender
            - defer: { task: clean }
    index:
        cmds:
            - echo "Building search index"
            - pagefind --root-selector="main" --logfile search-log.log --silent --site public --output-subdir search/pagefind
    upload:
        env:
            AWS_ACCESS_KEY_ID: ""
            AWS_SECRET_ACCESS_KEY: ""
            CLOUDFRONT_DIST_ID: ""
        preconditions:
            - test -d public
        cmds:
            - echo "Uploading files"
            - aws s3 sync public/ s3://degruchy.org --storage-class REDUCED_REDUNDANCY --quiet --delete --exclude "*.csv" --exclude "*.caption" --exclude "*.DS_Store" --exclude ".DS_Store"
            - defer: { task: clean }
            - echo "Invalidating caches"
            - aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DIST_ID --paths "/*" >/dev/null
    clean:
        preconditions:
            - test -d public
            - test -d resources
            - test -f search-log.log
        cmds:
            - echo "Cleaning up build artefacts"
            - rm search-log.log
            - rm -r public
            - rm -r resources
    check_dependencies:
        cmds:
            - for: ['pagefind', 'hugo', 'aws']
              cmd: test -x $(which {{ .ITEM }})

This ends up being slightly easier to read and maintain. Each bit has it’s own section and commands, preconditions and even environments are handled in a purpose-driven way that makes it more clear what that section is for. It’s still YAML, though, so yuck.

However, I think I’ll give this a spin for a while and see how I like it. make has the ~49 year advantage over task, but not all new software is bad, it just has to prove itself. make has, but it’s grown warts over that time, and unless you’re doing dead simple stuff, it may be more confusing to write than YAML. In fact, I had Claude write the loop for me, and some of the other parts because the syntax is… terse.

Respond via email.