new-ryuslash.org/build.org

8.5 KiB
Raw Permalink Blame History

ryuslash's website's build's files

I'm a big fan of Literate Programming, so I figured I'd make the builds for my website a literate configuration file as well.

First I need to build the build files. This is the smallest make file that I can think to make to enable me to build the rest out. This make file is duplicated in both this file and the source code repository since I don't know of a way not to.

First I define a function tangle that can be used to tangle an org file to the code file that it needs to be. Then I specify that any .mk file should depend on this file ({{{input-file}}}) and that it is generated by running org-babel-tangle-file on it. The $< is the first dependency and $@ is the current target file (whatever .mk file we're generating).

define tangle =
	eldev emacs -quick -batch \
	    -eval "(package-initialize)" \
	    -load ob-tangle \
	    -eval "(org-babel-tangle-file \"$<\" \"$(PWD)/$@\"$(if $1, \"$1\"))"
endef

%.mk: build.org
	$(call tangle)

After that it's just a matter of including the file I want.

  include build.mk

GNU Make (I don't know about other makes) will see if there is a recipe to make the file it wants to include and will try and run it before trying to include the file. This combined with our %.mk target ensures that make will always try to recreate the build.mk file when {{{input-file}}} is updated.

Makefile

This is the actual make file that builds and deploys my site. It's all put into the build.mk file and executed from there. The %.mk pattern rule thankfully doesn't get recognized as a make target, so the first target define in the included file is assumed to be the default target.

First off I specify the help target. This target parses the make files and extracts targets that include some comment on what they do. This target should come first so that it automatically becomes the default target. This way when I run just make I can see which targets I have available. I got this awesome trick from Victoria Drakes article How to create a self-documenting Makefile.

help:							## Show this help
	@grep --extended-regexp --no-filename '^[^#].*?\s##\s' $(MAKEFILE_LIST) \
	    | sort \
	    | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

The build target converts everything from whatever source files they are to html and css. The build target has 2 other targets it depends on, not surprisingly html and css. The html and css targets don't have any comment because they're not really meant to be executed directly.

build: html css			  ## Build the site and copy it to the staging directory

The html target calls Emacs. It depends on the Eldev file having been generated to specify any additional dependencies and which package archives should be used and this file will be generated by the Eldev target.

html: Eldev
	@echo "Publishing..."
	eldev emacs --quick --batch --load publish.el --funcall org-publish-all

The css target does specify its dependencies. This is both an exercise in writing make files (which I generally quite enjoy), and also to make sure that my builds don't take too long unless they actually have to. Ultimately any .css file gets created from a .less file by calling the lessc program. I'm intentionally not using recursive make in this project because it slows make down a lot, and I don't have to manage several make files this way.

css: public/assets/css/main.css public/assets/css/tekuti.css public/assets/css/cgit.css

public/assets/css/main.css public/assets/css/tekuti.css public/assets/css/cgit.css: \
    src/less/include/common.less \
    src/less/include/components.less \
    src/less/include/colors.less \
    src/less/yoshi.css

public/assets/css/%.css: src/less/%.less
	lessc $< $@

The deploy target first makes sure that build has been executed at least once and then uses rsync to upload all of the files. This intentionally doesn't depend on the build target so that I can upload whatever I happen to have generated without being forced to rebuild.

deploy:							## Deploy the site to live
	@[[ -e public/index.html ]] || (echo "Run 'make build' before deploy" && exit 1)
	rsync --verbose --checksum --recursive --delete \
	    --exclude '*~' --exclude '.eldev' --delete-excluded \
	    public/ ryuslash.org:ryuslash-next/

The clean target makes sure that everything that is generated gets cleaned up again. This is important if I need to start with a clean slate.

clean:							## Remove all of the build files
	@echo "Cleaning up..."
	@rm -rvf *.elc
	@rm -rvf public
	@rm -rvf .org-timestamps
	@rm -rvf posts/index.org build.mk Eldev

The serve target is a convenience target for when I'm writing or making modifications to the build and publish processes. It just starts a simple php web server in the public/ directory so that I can easily load it in my browser.

serve:						   ## Run a simple web server to look at the results
	@cd public && php -S "localhost:8000"

The theme target is another convenience target. I generate the colors for the source code blocks on my site from my Emacs theme. This target exports the colors from my theme so that the code blocks can use them. This file is then included by the less files. There is no good dependency here, because there is no file for the export of my theme to depend on right now, just occasionally I have to run it. It does depend on the Eldev file having been generated.

I keep this particular target around for playing with, but right now it doesn't actually work. Just because even though I load and enable yoshi-theme it doesn't appear to apply the theme in a batch session. Seems understandable because no UI actually gets loaded, but that does mean that it can't figure out which faces it sets and it just outputs the colors for the default theme.

theme: Eldev					## Generate the theme CSS
	eldev emacs --quick --batch --load htmlize --load ox-html \
	    -eval "(setq org-html-htmlize-output-type 'css)" \
	    -funcall org-html-htmlize-generate-css \
	    -load yoshi-theme \
	    -eval "(enable-theme 'yoshi)" \
	    -load make-mode \
	    -eval "(kill-whole-line)" \
	    -eval "(kill-whole-line)" \
	    -eval "(goto-char (point-max))" \
	    -eval "(forward-line -2)" \
	    -eval "(kill-whole-line)" \
	    -eval "(kill-whole-line)" \
	    -eval "(css-mode)" \
	    -eval "(indent-region (point-min) (point-max))" \
	    -eval '(write-file "src/less/yoshi.css")'

The Eldev target just tangles the {{{input-file}}} into the Eldev file. This uses the tangle function defined in the intro section.

Eldev: build.org
	$(call tangle)

Finally, as a precaution, I specify that all of the main targets are phony targets. This way if I ever introduce any file with the same name as these targets they will still build and not assume that because the file exists, everything is up-to-date.

.PHONY: publish deploy html css help theme

Eldev

With Eldev I can install dependencies of my publish.el locally. Really the only reason I chose to use Eldev is because it is available in the Guix repository.

Since this is an actually full-fledged Emacs Lisp file and I don't know what I'm going to be doing in the future, I should be sure to enable lexical binding. Otherwise Emacs defaults to using dynamic binding, and that might cause some surprises in the future, since I'm quite used to using lexical binding everywhere.

; -*- lexical-binding: t -*-

All I'm doing here, really, is enable the various Emacs Lisp Package Archives.

(eldev-use-package-archive 'gnu)
(eldev-use-package-archive 'nongnu)
(eldev-use-package-archive 'melpa)

COMMENT Local Variables