From 6402e2e73e2cad23b51975053fe6f52742070033 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Tue, 25 Jul 2023 22:26:52 -0700 Subject: [PATCH] Move make file build targets into literate document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All of the make targets and recipes have been moved into ‘bootstrap.org’ so that they can be documented. Tangling this document will result in a ‘bootstrap.mk’ which contains all of the targets and recipes from the org document. The GNUmakefile now only has just enough to know how to generate ‘bootstrap.mk’ and that it needs to generate ‘bootstrap.mk’. --- .gitignore | 5 +- GNUmakefile | 47 +++--------------- bootstrap.org | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 42 deletions(-) create mode 100644 bootstrap.org diff --git a/.gitignore b/.gitignore index c00e0b9..1dde023 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ /.cask -/public /.org-timestamps + +# Built files +/public /posts/index.org +/bootstrap.mk # Added automatically by `eldev init'. /.eldev diff --git a/GNUmakefile b/GNUmakefile index ff7fdd1..09035f8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,42 +1,7 @@ -.PHONY: publish deploy html css help theme +%.mk: bootstrap.org + eldev emacs -quick -batch \ + -eval "(package-initialize)" \ + -load ob-tangle \ + -eval "(org-babel-tangle-file \"$<\" \"$(PWD)/$@\" \"makefile\")" -help: ## Show this help - @egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' - -publish: html css ## Build the site and copy it to the staging directory - -deploy: ## Deploy the site to live - @[[ -e public/index.html ]] || (echo "Run make publish before deploy" && exit 1) - rsync --rsh="ssh -p 4511" --verbose --checksum --recursive --delete \ - --exclude '*~' --exclude '.eldev' --delete-excluded \ - public/ ryuslash.org:ryuslash-next/ - -html: - @echo "Publishing..." - eldev emacs --quick --batch --load publish.el --funcall org-publish-all - -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 - -public/assets/css/%.css: src/less/%.less - lessc $< $@ - -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 - -serve: ## Run a simple web server to look at the results - @cd public && php -S localhost:8000 - -theme: ## 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 \ - -eval '(write-file "src/less/yoshi.css")' +include bootstrap.mk diff --git a/bootstrap.org b/bootstrap.org new file mode 100644 index 0000000..5fe93a8 --- /dev/null +++ b/bootstrap.org @@ -0,0 +1,131 @@ +#+title: ryuslash's website's bootstrap +#+subtitle: Literate configuration of how to build this site +#+options: num:nil prop:t + +I'm a big fan of [[file:literate-programming.org][Literate Programming]], so I figured I'd make the builds for my website a literate configuration file as well. + +First I need to bootstrap the bootstrap. 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 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). + +#+begin_src makefile :tangle no + %.mk: bootstrap.org + eldev emacs -quick -batch \ + -eval "(package-initialize)" \ + -load ob-tangle \ + -eval "(org-babel-tangle-file \"$<\" \"$(PWD)/$@\" \"makefile\")" +#+end_src + +After that it's just a matter of including the file I want. + +#+begin_src makefile :tangle no + include bootstrap.mk +#+end_src + +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 =bootstrap.mk= file when ={{{input-file}}}= is updated. + +* Makefile +:PROPERTIES: +:header-args:makefile: :tangle bootstrap.mk +:END: + +This is the actual make file that builds and deploys my site. It's all put into the =bootstrap.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 [[https://victoria.dev/][Victoria Drake]]’s article [[https://victoria.dev/blog/how-to-create-a-self-documenting-makefile/][How to create a self-documenting Makefile]]. + +#+begin_src 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}' +#+end_src + +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. + +#+begin_src makefile +build: html css ## Build the site and copy it to the staging directory +#+end_src + +The =html= target calls Emacs. It has no dependencies because the org-mode publishing method takes care of making sure that nothing gets built unless necessary. + +#+begin_src makefile +html: + @echo "Publishing..." + eldev emacs --quick --batch --load publish.el --funcall org-publish-all +#+end_src + +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. + +#+begin_src makefile +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 $< $@ +#+end_src + +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. + +#+begin_src makefile +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/ +#+end_src + +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. + +#+begin_src makefile +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 bootstrap.mk +#+end_src + +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. + +#+begin_src makefile +serve: ## Run a simple web server to look at the results + @cd public && php -S "localhost:8000" +#+end_src + +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. + +#+begin_src makefile +theme: ## 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")' +#+end_src + +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. + +#+begin_src makefile +.PHONY: publish deploy html css help theme +#+end_src + +* COMMENT Local Variables + +# Local Variables: +# org-src-preserve-indentation: t +# End: