├── LICENSE ├── update-submodule.sh ├── page.template ├── devd.sh ├── CONTRIBUTING ├── linkchecker.sh ├── mdlstyle.rb ├── makedown.conf ├── genwikilinks.sh ├── find.sh ├── README.md ├── Makefile └── makedown.sh /LICENSE: -------------------------------------------------------------------------------- 1 | makedown is in the public domain. 2 | 3 | To the extent possible under law, Kylie McClain 4 | has waived all copyright and related or neighboring rights to this work. 5 | 6 | http://creativecommons.org/publicdomain/zero/1.0/ 7 | -------------------------------------------------------------------------------- /update-submodule.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -xe 4 | before=$(git -C makedown rev-parse --short HEAD) 5 | git submodule update --checkout --remote --force makedown 6 | PAGER=cat git diff --submodule makedown 7 | after=$(git -C makedown rev-parse --short HEAD) 8 | git add -v makedown 9 | git commit -o makedown -m "Update makedown (${before}..${after})" 10 | 11 | -------------------------------------------------------------------------------- /page.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <?makedown title?> 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |

13 |
14 |
15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /devd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # devd.sh 4 | # part of makedown, a build system for making markdown websites. 5 | # https://github.com/somasis/makedown 6 | # 7 | # starts up an instance of the devd server, then gets the address and PID of it, 8 | # so that it can be killed once it is no longer needed. 9 | # 10 | 11 | [ -n "${WORK}" ] || exit 127 12 | 13 | set -x 14 | nohup devd "${@}" "${WORK}" > "${WORK}"/devd.log & 15 | echo $! > "${WORK}"/devd.pid 16 | sleep 1 17 | sed -r '/Listening/!d;s/Listening on (.+) .*/\1/' "${WORK}"/devd.log > "${WORK}"/devd.address 18 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | When contributing your first changes, please include an empty commit for 2 | copyright waiver using the following message (replace 'Jane Doe' with 3 | your name or nickname): 4 | 5 | Jane Doe Copyright Waiver 6 | 7 | I dedicate any and all copyright interest in this software to the 8 | public domain. I make this dedication for the benefit of the public at 9 | large and to the detriment of my heirs and successors. I intend this 10 | dedication to be an overt act of relinquishment in perpetuity of all 11 | present and future rights to this software under copyright law. 12 | -------------------------------------------------------------------------------- /linkchecker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # linkchecker.sh 4 | # part of makedown, a build system for making markdown websites. 5 | # https://github.com/somasis/makedown 6 | # 7 | # runs linkchecker on the devd server started prior to running 8 | # the script. 9 | # 10 | 11 | [ -n "${WORK}" ] || exit 127 12 | 13 | set -x 14 | linkchecker --check-extern --no-robots "$@" $(cat "${WORK}"/devd.address) & 15 | linkchecker_pid=$! 16 | trap 'kill $linkchecker_pid' SIGINT 17 | wait 18 | linkchecker_exit=$? 19 | trap - SIGINT 20 | 21 | kill $(cat "${WORK}"/devd.pid) 22 | rm "${WORK}"/devd.pid "${WORK}"/devd.address 23 | if [ $linkchecker_exit -ne 0 ];then 24 | exit 1 25 | fi 26 | -------------------------------------------------------------------------------- /mdlstyle.rb: -------------------------------------------------------------------------------- 1 | # mdlstyle.rb - style configuration for markdownlint. 2 | # part of makedown, a build system for making markdown websites. 3 | # https://github.com/somasis/makedown 4 | 5 | rule 'MD003', :style => :atx # atx style headers 6 | rule 'MD004', :style => :dash # enforce dashes for unordered lists 7 | rule 'MD007', :indent => 4 # four spaces for indentation 8 | rule 'MD013', :code_blocks => false # don't check line length in code blocks 9 | rule 'MD013', :tables => false # don't check line length in tables 10 | rule 'MD013', :line_length => 100 # 100 length limit 11 | rule 'MD026', :punctuation => ".,;:" # allow !? at header end 12 | rule 'MD029', :style => :ordered # enforce incremental ordered lists 13 | 14 | exclude_rule 'MD013' # line length is stupid... disable it now 15 | exclude_rule 'MD022' # don't enforce spaces on both sides of headers. used by makedown.sh, for page title and description. also it looks better. 16 | exclude_rule 'MD025' # allow multiple top level, because we want to be in-depth in our doc 17 | exclude_rule 'MD036' # allow emphasis "used instead of a header" because we're using emphasis without desire for a header 18 | exclude_rule 'MD039' # currently there's a bug with this: https://github.com/markdownlint/markdownlint/issues/182 19 | -------------------------------------------------------------------------------- /makedown.conf: -------------------------------------------------------------------------------- 1 | # SITE_NAME = 2 | # Site's name, used in page titles 3 | # A page named "" will have that as the page title 4 | # any other page will be named " - " 5 | 6 | SITE_NAME = makedown 7 | 8 | # WIKI_LINKS = 9 | # Whether to generate wiki-style links for all pages in the site, including 10 | # links to the headers/sections of pages. 11 | # 12 | # This means that you will be able to link to other pages on the site without 13 | # having to declare them in the markdown file prior to their usage. 14 | # 15 | # Link formats are [Page Title], and [Page Title#Section name] 16 | 17 | WIKI_LINKS = true 18 | 19 | # CHECK_LINKS_ON_WATCH = 20 | # Whether to run `make check-links` on all files when `make watch` is ran. 21 | # 22 | # Usually this slows things down a lot, so when it's set "false" only `lint` 23 | # will be ran instead. 24 | 25 | CHECK_LINKS_ON_WATCH = false 26 | 27 | # MARKDOWN_FLAGS = 28 | # Flags (not arguments, markdown(1) -f flags) to pass to `markdown` when it is ran. 29 | 30 | MARKDOWN_FLAGS = alphalist,autolink,divquote,definitionlist,dldiscount,dlextra,emphasis,ext,fencedcode,footnotes,githubtags,html,image,latex,links,smarty,strict,strikethrough,style,superscript,tables,tabstop,html5anchor 31 | 32 | # DEPLOY_ARGS = 33 | # Arguments to pass to `rsync` when `deploy` is ran. 34 | # 35 | # Useful for excluding files, mostly. 36 | 37 | DEPLOY_ARGS = 38 | 39 | # DEVD_ARGS = 40 | # Arguments to pass to `devd` when it is used. 41 | 42 | DEVD_ARGS = 43 | 44 | # LINKCHECKER_ARGS = 45 | # Arguments to pass to `linkchecker` when `check-links` is ran. 46 | 47 | LINKCHECKER_ARGS = 48 | -------------------------------------------------------------------------------- /genwikilinks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # genwikilinks.sh 4 | # part of makedown, a build system for making markdown websites. 5 | # https://github.com/somasis/makedown 6 | # 7 | # generates a list of links to each page, based on directory structure, as well 8 | # as each header in each page. idea being that you can then insert them into the 9 | # end of markdown, before rendering to HTML, and thus get a sort of wiki-style 10 | # functionality of easy page linking. 11 | # 12 | # example output: 13 | # [Alternatives]: /alternatives.html 14 | # [Alternatives#Alternatives]: /alternatives.html#Alternatives 15 | # [Alternatives#Alternative Libraries and Programs]: /alternatives.html#Alternative-Libraries-and-Programs 16 | # [Alternatives#Compression/Decompression]: /alternatives.html#Compression/Decompression 17 | # 18 | 19 | set -e 20 | 21 | gen() { 22 | pwd_escaped=$(printf '%s' "${PWD}" | sed 's/[\/&]/\\&/g') 23 | for f in "$@";do 24 | if [ $(sed '1!d' "${f}" | grep -c '^# ') -eq 1 ];then 25 | title=$(sed '1!d;s/^# //' "${f}") 26 | title_esc=$(printf '%s' "${title}" | sed 's/\//\\\//g') 27 | f_full=$(readlink -f "${f}" | sed "s/${pwd_escaped}//;s/\.md$/\.html/") 28 | f_esc=$(printf '%s' "${f_full}" | sed 's/\//\\\//g') 29 | printf "[%s]: %s\n" "${title}" "${f_full}" 30 | markdown -f toc,html,html5anchor -T "${f}" | \ 31 | sed -r \ 32 | -e "/|<\/a>(.*)<\/h[1-6]>/[${title_esc}#\2]: ${f_esc}#\1/" 36 | fi 37 | done 38 | } 39 | 40 | if [ "${1}" = --gen ];then 41 | shift 42 | # redirect to file because else the directory cutting in find.sh eats gen's output 43 | gen "$@" >> "${WORK}"/.genwikilinks_tmp 44 | exit $? 45 | fi 46 | 47 | [ -n "${SRCDIR}" ] || exit 127 48 | [ -n "${MAKEDOWN}" ] || exit 127 49 | [ -n "${WORK}" ] || exit 127 50 | 51 | self=$(readlink -f "${0}") 52 | output="${1}" 53 | 54 | cd "${SRCDIR}" 55 | 56 | rm -f "${WORK}"/.genwikilinks_tmp 57 | "${MAKEDOWN}"/find.sh pages -exec "${self}" --gen {} \; 58 | grep '^\[' "${WORK}"/.genwikilinks_tmp > "${output}" 59 | rm -f "${WORK}"/.genwikilinks_tmp 60 | -------------------------------------------------------------------------------- /find.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # find.sh 4 | # part of makedown, a build system for making markdown websites. 5 | # https://github.com/somasis/makedown 6 | # 7 | # uses `find` to get a list of files matching , with some exclusions. 8 | # also, gets a relative pathname. 9 | # 10 | 11 | if [ "${1}" = --absolute ];then 12 | absolute=true 13 | srcdir_count=0 14 | shift 15 | else 16 | absolute=false 17 | fi 18 | 19 | type="${1}"; shift 20 | [ -n "${SRCDIR}" ] || exit 127 21 | [ -n "${MAKEDOWN}" ] || exit 127 22 | [ -n "${WORK}" ] || exit 127 23 | 24 | [ "${absolute}" = true ] || srcdir_count=$(( $(printf '%s' "${SRCDIR}"/ | tr -cd '/' | wc -c) + 1 )) 25 | 26 | cd "${SRCDIR}" 27 | 28 | _find() { 29 | path="$1"; shift 30 | if [ "${absolute}" = true ];then 31 | find "$path" \ 32 | \! \( -name ".*" \) \ 33 | \! \( -path "${SRCDIR}/*.*/*" -prune \) \ 34 | \! \( -path "${MAKEDOWN}/*" -prune \) \ 35 | \! \( -path "${WORK}/*" -prune \) \ 36 | "$@" 37 | else 38 | find "$path" \ 39 | \! \( -name ".*" \) \ 40 | \! \( -path "${SRCDIR}/*.*/*" -prune \) \ 41 | \! \( -path "${MAKEDOWN}/*" -prune \) \ 42 | \! \( -path "${WORK}/*" -prune \) \ 43 | "$@" | cut -d'/' -f${srcdir_count}- 44 | fi 45 | } 46 | 47 | case "${type}" in 48 | pages) 49 | _find "${SRCDIR}" \ 50 | \( -type f -o -type l -a -xtype f \) \ 51 | -name '*.md' \ 52 | "$@" 53 | ;; 54 | script) 55 | _find "${SRCDIR}" \ 56 | \( -type f -o -type l -a -xtype f \) \ 57 | -name '*.js' \ 58 | "$@" 59 | ;; 60 | style) 61 | _find "${SRCDIR}" \ 62 | \( -type f -o -type l -a -xtype f \) \ 63 | -name '*.css' \ 64 | "$@" 65 | ;; 66 | aux) 67 | _find "${SRCDIR}" \ 68 | \( -type f -o -type l -a -xtype f \) \ 69 | \! \( \ 70 | -name '*.md' \ 71 | -o -name '*.js' \ 72 | -o -name '*.css' \ 73 | -o -name '*.template' \ 74 | -o -name 'makedown.conf' \ 75 | -o -name 'Makefile.local' \ 76 | -o -name 'Makefile' \ 77 | \) \ 78 | "$@" 79 | ;; 80 | dir) 81 | _find "${SRCDIR}" \ 82 | \( -type d -o -type l -a -xtype d \) \ 83 | \! \( \ 84 | -name '.*' \ 85 | -o -name 'makedown' \ 86 | \) \ 87 | "$@" 88 | esac 89 | 90 | 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # makedown 2 | 3 | makedown is a build system for generating static websites. 4 | 5 | ## Requirements 6 | 7 | ### Building 8 | 9 | - [GNU `make`](https://www.gnu.org/software/make/) 10 | - [discount `markdown`](http://www.pell.portland.or.us/~orc/Code/discount/) (at least version 2.2.2) 11 | 12 | ### Checking 13 | 14 | - [markdownlint](https://github.com/markdownlint/markdownlint) 15 | - [devd](https://github.com/cortesi/devd) 16 | - [linkchecker](https://wummel.github.io/linkchecker) 17 | 18 | ### Deploying 19 | 20 | - [rsync](https://rsync.samba.org/) 21 | 22 | ### Live rebuilding 23 | 24 | - [devd](https://github.com/cortesi/devd) 25 | - [entr](http://entrproject.org/) 26 | 27 | ## Usage 28 | 29 | 1. Clone this repository to a directory named "makedown" in the root of your site. 30 | 31 | $ cd www.makedown.gov 32 | $ ls -CFl 33 | total 16K 34 | -rw-r--r-- 1 somasis somasis 71 Nov 11 05:44 index.md 35 | -rw-r--r-- 1 somasis somasis 421 Nov 11 05:51 page.template 36 | $ git clone https://github.com/somasis/makedown 37 | Cloning into 'makedown'... 38 | remote: Counting objects: 11, done. 39 | remote: Compressing objects: 100% (11/11), done. 40 | remote: Total 11 (delta 0), reused 11 (delta 0), pack-reused 0 41 | Unpacking objects: 100% (11/11), done. 42 | 43 | If you are cloning it into an existing git repository, you'll want to have it be a submodule. 44 | 45 | $ git submodule add https://github.com/somasis/makedown makedown 46 | Cloning into '/home/somasis/git/somasis.com/makedown'... 47 | remote: Counting objects: 60, done. 48 | remote: Compressing objects: 100% (40/40), done. 49 | remote: Total 60 (delta 31), reused 48 (delta 19), pack-reused 0 50 | Unpacking objects: 100% (60/60), done 51 | $ git status 52 | On branch master 53 | Changes to be committed: 54 | (use "git reset HEAD ..." to unstage) 55 | 56 | new file: .gitmodules 57 | new file: makedown 58 | 59 | 2. Symbolically link the Makefile from the "makedown" directory to your root. 60 | 61 | $ ln -s ./makedown/Makefile Makefile 62 | 63 | 3. Make a `makedown.conf` file, and a `page.template`. There's example files in this repository. 64 | 65 | $ ls -CFl 66 | total 16K 67 | -rw-r--r-- 1 somasis somasis 71 Nov 11 05:44 index.md 68 | drwxr-xr-x 1 somasis somasis 220 Nov 11 05:55 makedown/ 69 | -rw-r--r-- 1 somasis somasis 18 Nov 11 05:51 makedown.conf 70 | lrwxrwxrwx 1 somasis somasis 17 Nov 11 05:44 Makefile -> makedown/Makefile 71 | -rw-r--r-- 1 somasis somasis 421 Nov 11 05:51 page.template 72 | 73 | 4. `make`, `make check`, `make deploy`. 74 | 75 | 5. When `makedown` gets some new commits, you want to update. 76 | 77 | If you're using it as part of a git repository, you want to update the submodule. 78 | 79 | $ git submodule update --checkout --remote makedown 80 | Submodule path 'makedown': checked out '4a2078479578c51f031fcd2ea341ca05ecea6005' 81 | $ git add -v makedown 82 | add 'makedown' 83 | $ git commit -v 84 | [master f57c37e] Update makedown 85 | 1 file changed, 1 insertion(+), 1 deletion(-) 86 | $ git push -v 87 | Pushing to git@github.com:somasis/www.makedown.gov.git 88 | Counting objects: 2, done. 89 | Delta compression using up to 4 threads. 90 | Compressing objects: 100% (2/2), done. 91 | Writing objects: 100% (2/2), 254 bytes | 254.00 KiB/s, done. 92 | Total 2 (delta 1), reused 0 (delta 0) 93 | remote: Resolving deltas: 100% (1/1), completed with 1 local object. 94 | To github.com:somasis/www.makedown.gov.git 95 | 3839b44..f57c37e master -> master 96 | updating local tracking ref 'refs/remotes/origin/master' 97 | 98 | (you can also just run `update-submodule.sh` from within the root repository to do this) 99 | 100 | If you're not, just pull the changes like any other git repository, with `git pull`. 101 | 102 | ## License 103 | 104 | **makedown** is in the public domain. 105 | 106 | To the extent possible under law, Kylie McClain 107 | has waived all copyright and related or neighboring rights to this work. 108 | 109 | 110 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/bin/make -f 2 | # 3 | # makedown - a build system for making markdown websites. 4 | # https://github.com/somasis/makedown 5 | # 6 | # requirements: 7 | # discount `markdown` (http://www.pell.portland.or.us/~orc/Code/discount/) 8 | # 9 | # `lint` requirements: 10 | # markdownlint (https://github.com/markdownlint/markdownlint) 11 | # 12 | # `check-links` requirements: 13 | # devd (https://github.com/cortesi/devd) 14 | # linkchecker (https://wummel.github.io/linkchecker) 15 | # 16 | # `deploy` requirements: 17 | # rsync (https://rsync.samba.org/) 18 | # 19 | # `watch` requirements: 20 | # devd (https://github.com/cortesi/devd) 21 | # entr (http://entrproject.org/) 22 | # 23 | 24 | export MAKEDOWN := $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))/makedown 25 | export SRCDIR := $(abspath $(MAKEDOWN)/..) 26 | export IMAGE ?= $(SRCDIR)/image 27 | export WORK ?= $(SRCDIR)/work 28 | 29 | ifneq "$(wildcard $(MAKEDOWN)/find.sh)" "$(MAKEDOWN)/find.sh" 30 | $(error Please don't try to run makedown from the directory of makedown's files) 31 | endif 32 | 33 | # HACK: `shell` doesn't take exported commands. this is ugly. :( 34 | PAGES = $(addprefix $(WORK)/,$(addsuffix .html,$(basename $(shell MAKEDOWN=$(MAKEDOWN) SRCDIR=$(SRCDIR) WORK=$(WORK) IMAGE=$(IMAGE) $(MAKEDOWN)/find.sh pages)))) 35 | STYLE = $(addprefix $(WORK)/,$(shell MAKEDOWN=$(MAKEDOWN) SRCDIR=$(SRCDIR) WORK=$(WORK) IMAGE=$(IMAGE) $(MAKEDOWN)/find.sh style)) 36 | SCRIPT = $(addprefix $(WORK)/,$(shell MAKEDOWN=$(MAKEDOWN) SRCDIR=$(SRCDIR) WORK=$(WORK) IMAGE=$(IMAGE) $(MAKEDOWN)/find.sh script)) 37 | AUX = $(addprefix $(WORK)/,$(shell MAKEDOWN=$(MAKEDOWN) SRCDIR=$(SRCDIR) WORK=$(WORK) IMAGE=$(IMAGE) $(MAKEDOWN)/find.sh aux)) 38 | 39 | include $(MAKEDOWN)/makedown.conf 40 | -include $(SRCDIR)/makedown.conf 41 | 42 | ifndef IMAGE 43 | $(error IMAGE should be set to a directory) 44 | endif 45 | 46 | ifndef WORK 47 | $(error WORK should be set to a directory) 48 | endif 49 | 50 | ifeq ($(WIKI_LINKS),true) 51 | WIKI_LINKS = $(WORK)/.makedown_wiki_links.tmp 52 | WIKI_LINKS_ARG = --append $(WIKI_LINKS) 53 | else 54 | ifeq ($(WIKI_LINKS),false) 55 | WIKI_LINKS = 56 | else 57 | $(error WIKI_LINKS should be set to true or false) 58 | endif 59 | endif 60 | 61 | ifdef MARKDOWN_FLAGS 62 | MARKDOWN_FLAGS := --flags "$(MARKDOWN_FLAGS)" 63 | endif 64 | 65 | ifdef SITE_NAME 66 | SITE_NAME_ARG = --name "$(SITE_NAME)" 67 | endif 68 | 69 | ifeq ($(CHECK_LINKS_ON_WATCH),true) 70 | CHECK_LINKS_ON_WATCH = check 71 | else 72 | ifeq ($(CHECK_LINKS_ON_WATCH),false) 73 | CHECK_LINKS_ON_WATCH = lint 74 | else 75 | $(error CHECK_LINKS_ON_WATCH should be set to true or false) 76 | endif 77 | endif 78 | 79 | export MARKDOWN_FLAGS 80 | export SITE_NAME 81 | 82 | all: makedown-all 83 | clean: makedown-clean 84 | check: makedown-check 85 | lint: makedown-lint 86 | check-links: makedown-check-links 87 | deploy: makedown-deploy 88 | watch: makedown-watch 89 | 90 | -include $(SRCDIR)/Makefile.local 91 | 92 | makedown-all: $(PAGES) $(STYLE) $(SCRIPT) $(AUX) 93 | makedown-clean: 94 | rm -f $(PAGES) 95 | rm -f $(STYLE) 96 | rm -f $(SCRIPT) 97 | rm -f $(AUX) 98 | rm -f $(WORK)/.makedown_wiki_links.tmp 99 | rm -f $(WORK)/devd.log $(WORK)/devd.pid $(WORK)/devd.address 100 | -find $(WORK) -type d -empty -print -delete 101 | 102 | makedown-check: lint check-links 103 | 104 | makedown-lint: all 105 | mdl -s $(MAKEDOWN)/mdlstyle.rb $(PAGES) 106 | 107 | makedown-check-links: all 108 | $(MAKEDOWN)/devd.sh $(DEVD_ARGS) -t 109 | $(MAKEDOWN)/linkchecker.sh $(LINKCHECKER_ARGS) 110 | 111 | $(WIKI_LINKS): 112 | @mkdir -p $(dir $@) 113 | $(MAKEDOWN)/genwikilinks.sh $(WIKI_LINKS) 114 | 115 | $(WORK)/%.html: $(SRCDIR)/%.md $($(MAKEDOWN)/makedown.sh --print-template "$<") $(WIKI_LINKS) 116 | @mkdir -p $(dir $@) 117 | $(MAKEDOWN)/makedown.sh $(MARKDOWN_FLAGS) $(SITE_NAME_ARG) $(WIKI_LINKS_ARG) "$<" > "$@" 118 | 119 | $(WORK)/%: $(SRCDIR)/% 120 | @mkdir -p $(dir $@) 121 | cp "$<" "$@" 122 | 123 | makedown-deploy: all 124 | rsync -v -rl --delete-after --exclude '.*' $(DEPLOY_ARGS) $(WORK)/ $(IMAGE) 125 | 126 | makedown-watch: all 127 | $(MAKEDOWN)/devd.sh $(DEVD_ARGS) 128 | -while true; do \ 129 | (for type in pages style script aux;do \ 130 | $(MAKEDOWN)/find.sh --absolute $${type} || exit 2; \ 131 | done) | entr -c sh -c '$(MAKE) WORK=$(WORK) $(CHECK_LINKS_ON_WATCH) all'; \ 132 | done 133 | kill $$(cat $(WORK)/devd.pid) 134 | 135 | .PHONY: all clean check lint check-links deploy watch 136 | .PHONY: makedown-all makedown-clean makedown-check makedown-lint makedown-check-links makedown-deploy makedown-watch 137 | -------------------------------------------------------------------------------- /makedown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # makedown.sh 4 | # part of makedown, a build system for making markdown websites. 5 | # https://github.com/somasis/makedown 6 | # 7 | # create nice HTML with `markdown` and add some templating functionality. 8 | # 9 | 10 | set -e 11 | 12 | stderr() { 13 | printf '%s: %s\n' "${0##*/}" "$*" >&2 14 | } 15 | 16 | edo() { 17 | stderr "$*" 18 | "$@" 19 | } 20 | 21 | die() { 22 | stderr "$1" 23 | exit $2 24 | } 25 | 26 | help() { 27 | printf '%s\n\n' \ 28 | "usage: ${0##*/} [--help] [--flags ] [--name ] [--append ] [--print-template] [--print-title] [--print-description] " 29 | printf ' %-10s %s\n' \ 30 | "--flags " "This argument is passed to \`markdown\`. Comma separated." \ 31 | "--print-template" "Print the template that would be used for generating 's HTML." \ 32 | "--print-title" "Print 's title." \ 33 | "--print-description" "Print 's description." \ 34 | "--append " "Markdown formatted file to append to the input before converting to HTML." \ 35 | "--name " "Set the site name. Used for setting the page titles." \ 36 | "--help" "This." 37 | } 38 | 39 | template_only=false 40 | title_only=false 41 | description_only=false 42 | 43 | if [ "${1}" = "--help" ] || [ $# -lt 1 ];then 44 | help 45 | exit 255 46 | fi 47 | 48 | while [ $# -ne 1 ];do 49 | case "${1}" in 50 | --flags) 51 | flags="${2}" 52 | shift 53 | ;; 54 | --append) 55 | append="${2}" 56 | shift 57 | ;; 58 | --name) 59 | site_name="${2}" 60 | shift 61 | ;; 62 | --print-template) 63 | template_only=true 64 | ;; 65 | --print-title) 66 | title_only=true 67 | ;; 68 | --print-description) 69 | description_only=true 70 | ;; 71 | esac 72 | shift 73 | done 74 | 75 | input="${1}" 76 | 77 | if [ -z "${input}" ];then 78 | help 79 | exit 255 80 | elif ! [ -r "${input}" ];then 81 | die "Can't read \"${input}\"." 13 82 | fi 83 | 84 | markdown_flags="-f toc,html5anchor${flags:+,${flags}}" 85 | 86 | temp_recurse() { 87 | # recurse to find parent templates 88 | base=$(basename "${input}" .md) 89 | old_pwd="${PWD}" 90 | cd "${dir}" 91 | until [ "${PWD}" = / ];do 92 | for f in "${PWD}"/${base}.template "${PWD}"/page.template;do 93 | [ -e "${f}" ] && printf '%s' "${f}" && return 0 94 | done 95 | cd .. 96 | done 97 | cd "${old_pwd}" 98 | stderr "couldn't find a template to use for \"${input}\"." 99 | return 1 100 | } 101 | 102 | finish() { 103 | rm -f "${body}" "${bodymd}" "${html}" "${html2}" "${toc}" "${temp}" "${temp2}" 104 | } 105 | 106 | trap finish EXIT 107 | 108 | dir=$(readlink -f "${input}") 109 | dir=${dir%/*} 110 | 111 | temp=$(temp_recurse "${input}") 112 | 113 | if [ "${template_only}" = true ];then 114 | printf '%s\n' "${temp}" 115 | temp= 116 | exit 0 117 | fi 118 | 119 | temp2=$(mktemp) 120 | stderr "cat \"${temp}\" > \"${temp2}\"" 121 | cat "${temp}" > "${temp2}" 122 | temp="${temp2}";temp2=$(mktemp) 123 | 124 | # Remove top markdown header; just the body is needed 125 | body=$(mktemp) 126 | bodymd=$(mktemp) 127 | html=$(mktemp) 128 | html2=$(mktemp) 129 | toc=$(mktemp) 130 | 131 | has_title=false 132 | has_description=false 133 | # # title\n 134 | if [ $(sed -n '1p' "${input}" | grep -Ec '^# ') -eq 1 ] && \ 135 | [ $(sed -n '2p' "${input}" | grep -Ec '^## ') -lt 1 ];then 136 | title=$(sed '1!d;s/^# //' "${input}") 137 | description= 138 | has_title=true 139 | has_description=false 140 | stderr "${input} has a title and no description" 141 | elif [ $(sed -n '1p;2p' "${input}" | grep -Ec '^#{1,2} ') -lt 2 ];then 142 | stderr "error: \"${input}\" should contain a title and description in the format of:" 143 | stderr "# Title" 144 | stderr "## Description." 145 | stderr "as the first two lines of the file." 146 | exit 5 147 | # # title\n## description\n 148 | else 149 | title=$(sed '1!d;s/^# //' "${input}") 150 | description=$(sed '2!d;s/^## //' "${input}") 151 | has_title=true 152 | has_description=true 153 | fi 154 | 155 | if [ "${title_only}" = true ];then 156 | "${has_title}" && printf '%s\n' "${title}" && exit 157 | exit 1 158 | elif [ "${description_only}" = true ];then 159 | "${has_description}" && printf '%s\n' "${description}" && exit 160 | exit 1 161 | fi 162 | 163 | 164 | title_unprefixed="${title}" 165 | 166 | # - , unless site name isn't set 167 | if [ -n "${site_name}" ] && [ "${title}" != "${site_name}" ];then 168 | title="${site_name} - ${title}" 169 | fi 170 | 171 | case ${has_title}${has_description} in 172 | truetrue) 173 | stderr "sed '1d;2d' \"${input}\" > \"${bodymd}\"" 174 | sed '1d;2d' "${input}" > "${bodymd}" 175 | ;; 176 | truefalse) 177 | stderr "sed '1d' \"${input}\" > \"${bodymd}\"" 178 | sed '1d' "${input}" > "${bodymd}" 179 | ;; 180 | *) 181 | exit 6 182 | ;; 183 | esac 184 | 185 | if [ -n "${append}" ];then 186 | stderr "cat \"${append}\" >> \"${bodymd}\"" 187 | cat "${append}" >> "${bodymd}" 188 | fi 189 | 190 | # FIXME: this would be better done in discount itself. 191 | # sed generates two anchors, one with dashes and one with underscores; however, it makes incorrect changes 192 | # with anchors that contain dashes. 193 | # avoids breaking mediawiki style anchor links. 194 | stderr "markdown ${markdown_flags} \"${bodymd}\" | sed -E '/^<\/a>$/ { p; s/-/_/g; }' > \"${body}\"" 195 | markdown ${markdown_flags} "${bodymd}" | sed -E '/^<\/a>$/ { p; s/-/_/g; }' > "${body}" 196 | 197 | stderr "markdown ${markdown_flags} -T -n \"${bodymd}\" > \"${toc}\"" 198 | markdown ${markdown_flags} -T -n "${bodymd}" > "${toc}" 199 | 200 | # get metadata about input file 201 | if git rev-parse HEAD >/dev/null 2>&1 && git ls-files --error-unmatch "${input}" >/dev/null 2>&1;then 202 | tree_commit=$(git rev-parse HEAD) 203 | file_commit=$(git log --format='%H' -1 "${input}") 204 | author=$(git shortlog -ns "${input}" | sed 's/.*\t//;s/$/,/') 205 | if [ $(printf '%s\n' "${author}" | wc -l) -gt 10 ];then 206 | author=$(printf '%s\n' "${author}" | head -n 10) 207 | author=$(printf '%s\n' "${author}" "...") 208 | fi 209 | author=$(printf '%s\n' "${author}" | tr '\n' ' ' | sed -E 's/,? $//') 210 | date=$(git log --date='format:%Y-%m-%d' --format='%ad' -1 "${input}") 211 | fi 212 | 213 | markdown_version=$(markdown ${markdown_flags} -VV) 214 | 215 | htmlescape() { 216 | printf '%s' "$@" | sed 's//\>/g;s/&/\&/g' 217 | } 218 | 219 | # we can definitely make this a dynamic thing, it'll have to use eval, though. 220 | tree_commit_escaped=$(htmlescape "$tree_commit") 221 | file_commit_escaped=$(htmlescape "$file_commit") 222 | site_name_escaped=$(htmlescape "$site_name") 223 | title_escaped=$(htmlescape "$title") 224 | title_unprefixed_escaped=$(htmlescape "$title_unprefixed") 225 | description_escaped=$(htmlescape "$description") 226 | author_escaped=$(htmlescape "$author") 227 | date_escaped=$(htmlescape "$date") 228 | markdown_version_escaped=$(htmlescape "${markdown_version}") 229 | 230 | edo sed \ 231 | -e "s||${tree_commit}|g" \ 232 | -e "s||${file_commit}|g" \ 233 | -e "s||${site_name}|g" \ 234 | -e "s||${title}|g" \ 235 | -e "s||${title_unprefixed}|g" \ 236 | -e "s||${description}|g" \ 237 | -e "s||${author}|g" \ 238 | -e "s||${date}|g" \ 239 | -e "s||${markdown_version}|g" \ 240 | -e "s||${tree_commit_escaped}|g" \ 241 | -e "s||${file_commit_escaped}|g" \ 242 | -e "s||${site_name_escaped}|g" \ 243 | -e "s||${title_escaped}|g" \ 244 | -e "s||${title_unprefixed_escaped}|g" \ 245 | -e "s||${description_escaped}|g" \ 246 | -e "s||${author_escaped}|g" \ 247 | -e "s||${date_escaped}|g" \ 248 | -e "s||${markdown_version_escaped}|g" \ 249 | "${temp}" > "${temp2}" 250 | edo sed \ 251 | "//{ 252 | r ${body} 253 | d 254 | }" "${temp2}" > "${html}" 255 | edo sed \ 256 | "//{ 257 | r ${toc} 258 | d 259 | }" "${html}" > "${temp2}" 260 | 261 | cat "${temp2}" 262 | --------------------------------------------------------------------------------