aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2022-08-14 08:54:15 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2022-08-14 08:54:15 +0200
commite3a075239cdf98e42435106d111b187d056c4150 (patch)
tree4f526a5f48efdb17ba628fb8e31fe3f699414ab4 /src
parenta8a05450f8056d8bbb7de8376118235b2578021a (diff)
downloadsebastiano.tronto.net-e3a075239cdf98e42435106d111b187d056c4150.tar.gz
sebastiano.tronto.net-e3a075239cdf98e42435106d111b187d056c4150.zip
Added blog post
Diffstat (limited to 'src')
-rw-r--r--src/blog/2022-08-14-website/website.md286
-rw-r--r--src/blog/blog.md1
-rw-r--r--src/blog/feed.xml7
3 files changed, 294 insertions, 0 deletions
diff --git a/src/blog/2022-08-14-website/website.md b/src/blog/2022-08-14-website/website.md
new file mode 100644
index 0000000..5ddcae0
--- /dev/null
+++ b/src/blog/2022-08-14-website/website.md
@@ -0,0 +1,286 @@
1# How I update my website
2
3When I created my website, I decided that I wanted to understand 100% of what
4I did. In practice, this means that I did not want to use any framework, not
5even a simple one. Someone might call this *minimalism*, someone else might
6call it *being a control freak*. I think I like the second one more.
7
8The principles I follow, which are actually an afterthought after a few months
9of trial-and-error, are roughly these:
10
11* **Minimalism**, a.k.a **control-freakism**: As mentioned above, I want to
12 only use tools that I understand completely,
13 at the cost of writing code by hand sometimes.
14* **Ease of use**: I want to write the bulk of my pages in
15 [Markdown](https://en.wikipedia.org/wiki/Markdown), which is easier to
16 read and edit than html code.
17* **Reproducibility**: Ideally, building new html pages (from a
18 newly-written Markdown document) and uploading them to my server
19 should be done by issuing simple commands such as `make` and `make deploy`.
20
21In more practical terms, this boils down to writing a couple of CSS and html
22files, writing a script that adds a header and a footer to the output of
23[lowdown](https://kristaps.bsd.lv/lowdown/), and using
24[rsync](https://en.wikipedia.org/wiki/Rsync) to deploy the files to my server.
25All of this is available on
26[my git page](https://git.tronto.net/sebastiano.tronto.net/), but I won't
27explain every detail of these build scripts here. In particular, my script
28also builds a [gemini](https://sebastiano.tronto.net/blog/2022-06-04-gemini/)
29version of my website, which I won't discuss here.
30
31## Prerequisites
32
33My website is hosted on an OpenBSD virtual machine in a remote server. I can
34access this virtual machine via
35[SSH](https://en.wikipedia.org/wiki/Secure_Shell), which gives me root
36access to the operating system. I use rsync for uploading my files to this
37server. As long as you have an http server that can serve static html
38files and a way to upload your files to this server, you can easily manage
39your website in a similar way. I am not going to explain how to do all of this
40here; if you need help I suggest you have a look at
41[Roman Zolotarev's website](https://rgz.ee).
42
43As for my local machine, the one I am actually using to write these blog
44posts, I just use a Markdown translator, a text editor, rsync
45and other basic UNIX tools.
46
47## Directory structure
48
49In my working directory
50there are two main folders with the exact same sub-folder structure: the first
51one is `src`, which contains all the markdown files I write, plus any other
52file I need for my pages, such as pictures; the other is `http`, which contains
53the html pages exactly as they are on my website. The `http` folder is
54generated from the src folder when I run the `build.sh` script - more
55on this later! (You won't find the `http` folder on my git page)
56
57There is one small caveat here:
58I like my urls to be clean and I want them stripped of the `.html`
59extension. To do this, I set up my `src` folder so that every
60subfolder contains at most one `.md` (Markdown) file, which is converted to
61an `index.html` file in the corresponding subfolder of `http`.
62In practice, if there are the following files:
63
64```
65├── src
66│   ├── git
67│   │   └── git-or-any-other-name.md
68```
69
70The following is generated by `build.sh`:
71
72```
73├── http
74│   ├── git
75│   │   └── index.html
76```
77
78So that when one accesses
79[sebastiano.tronto.net/git](https://sebastiano.tronto.net/git/)
80the web server automatically serves the `index.html` file.
81Without this trick the correct URL would have been
82`sebastiano.tronto.net/git.html` or something, which I don't like.
83
84The main working directory also contains the
85[`top.html`](https://git.tronto.net/sebastiano.tronto.net/file/top%2Ehtml%2Ehtml)
86and
87[`bottom.html`](https://git.tronto.net/sebastiano.tronto.net/file/bottom%2Ehtml%2Ehtml)
88files. These files are not uploaded directly to my server - they are not
89even well-formed html files! - but they are used to build all other
90html pages.
91
92## Building the pages
93
94The basic idea behind `build.sh` is very simple. If we want to create the
95html file corresponding to, say, `src/page/file.md`, we just need to create
96a file called `http/page/index.html` and copy there the contents of
97`top.html`, followed by the output of `lowdown src/page/file.md`, followed
98by the contents of `bottom.html`. In shell language:
99
100```
101cat top.html > http/page/index.html
102lowdown src/page/file.md >> http/page/index.html
103cat bottom.html >> http/page/index.html
104```
105
106Of course you don't have to use lowdown as I do: any Markdown translator
107works. Indeed, if you want to use a different markup language to write
108your pages you just need to replace the second line in the code above.
109
110We would also like to make a small change to the header while
111we build this page, namely we want the title of the page (the one
112displayed in your browser's top bar or tab) to match the actual
113title of the page or blog post. To do this easily I have left a
114placeholder `TITLE` in `top.html`, that we just need to replace with the
115actual title of the page. To find out what the title is we just need to
116get the text following
117the first `# ` (hash space) in the Markdown file - that is, the first
118"big title" of the page. We can do this
119thanks to the classic UNIX tools sed, grep and head:
120
121```
122sed "s/TITLE/$(grep '^\# ' < src/page/file.md \
123 | head -n 1 | sed 's/^\# //')/" < top.html > http/page/index.html
124lowdown src/page/file.md >> http/page/index.html
125cat bottom.html >> http/page/index.html
126```
127
128The first two lines might be a bit complicated to work out if you
129are not familiar with these commands. Let's break them down!
130
131The main command is `sed "s/TITLE/...stuff.../"` which replaces the
132first occurrence of the string `TITLE` with that complicated stuff.
133The end of the second line tells sed to use `top.html` as input and
134write the output to `http/page/index.html`. The complicated stuff
135that is going to replace `TITLE` is enclosed in `$()`, which means
136that it is the result of a command. This command is itself a chain
137of commands: first we find all lines that start with `# ` with
138`grep '^\# '` on the correct file (`< src/page/file.html`), then
139we take the first of these lines (`head -n 1`) and finally we
140trim the leading `# ` with `sed`. As you can see, the UNIX shell
141is quite a powerful tool!
142
143Now we just need to do all of this recursively on the `src` folder.
144The final result looks something like this:
145
146```
147#!/bin/sh
148
149recursivebuild() {
150 local destdir=$(echo $1 | sed 's|^src|http|')
151 mkdir -p "$destdir"
152 for file in $(ls $1); do
153 if [ -d "$1/$file" ]; then
154
155 # Recursively build subdirectories
156 mkdir -p "$destdir/$file"
157 recursivebuild "$1/$file"
158 else
159 extension=$(echo "$file" | sed 's/.*\.//')
160 if [ "$extension" = "md" ]; then
161
162 # Process Markdown files, as above
163 sed "s/TITLE/$(grep '^\# ' < "$1/$file" \
164 | head -n 1 \
165 | sed 's/^\# //')/" < top.html \
166 > "$destdir/index.html"
167 lowdown "$1/$file" >> "$destdir/index.html"
168 cat bottom.html >> "$destdir/index.html"
169 else
170
171 # Copy all other files as they are
172 cp "$1/$file" "$destdir/$file"
173 fi
174 fi
175 done
176}
177
178recursivebuild src
179```
180
181## Extras: the blog index and RSS feed
182
183The [blog index page](https://sebastiano.tronto.net/blog/) is also
184generated by the build script, but the corresponding Markdown file
185in `src` is not created by hand. Instead, this file is generated by
186scanning the `src/blog` subfolder. For each post, the date is deduced
187from the name of the folder containing the markdown file, which always
188starts with the date itself in the `yyyy-mm-dd` format.
189
190While we scan the blog directory to create a list of posts, we might as
191well make an [RSS feed](https://en.wikipedia.org/wiki/RSS) file for the
192blog. This is a file used by feed reader applications to check if there
193is any new post. The format is quite simple: check out
194[mine](https://sebastiano.tronto.net/blog/feed.xml).
195
196The code to accomplish this looks something like this:
197
198```
199makeblog() {
200 bf=src/blog/blog.md # Blog index file
201 ff=src/blog/feed.xml # RSS feed file
202
203 printf "# Blog\n\n[RSS Feed](feed.xml)\n\n" > $bf
204 cp feed-top.xml $ff
205
206 for i in $(ls src/blog | sort -r); do
207 if [ -d src/blog/$i ]; then
208
209 # Get basic data of the post (date, title)
210 f="src/blog/$i/*.md"
211 d=$(echo $i | grep -oE '^[0-9]{4}-[0-9]{2}-[0-9]{2}')
212 t=$(head -n 1 $f | sed 's/# //')
213
214 # Add blog post to the list
215 echo "* $d [$t]($i)" >> $bf
216
217 # Create RSS feed item
218 echo "<item>" >> $ff
219 echo "<title>$t</title>" >> $ff
220 echo "<link>https://sebastiano.tronto.net/blog/$i</link>" >> $ff
221 echo "<description>$t</description>" >> $ff
222 echo "<pubDate>$d</pubDate>" >> $ff
223 echo "</item>" >> $ff
224 echo "" >> $ff
225 fi
226 done
227
228 # Close the RSS feed file
229 echo "" >> $ff
230 echo "</channel>" >> $ff
231 echo "</rss>" >> $ff
232}
233```
234
235## Deploying with make
236
237Updating or adding a page is now very easy: I just need to edit the
238corresponding Markdown file, run `./build.sh` to build the new html
239pages and run
240
241```
242rsync -rv --delete --rsync-path=openrsync http/ \
243 tronto.net:/var/www/htdocs/sebastiano.tronto.net
244```
245
246to sync the `http` directory with my server. I need to use the
247`--rsync-path` option because the `rsync` binary has a different
248name on my local system (Linux) than on my server (OpenBSD). But apart from
249this the command is straightforward.
250
251Of course I don't want to type this lenghty command every time. It is very
252convenient in this case to write a short Makefile:
253
254```
255all: clean
256 ./build.sh
257
258clean:
259 rm -r http
260 mkdir -p http
261
262deploy:
263 rsync -rv --delete --rsync-path=openrsync http/ \
264 tronto.net:/var/www/htdocs/sebastiano.tronto.net
265
266.PHONY: all clean deploy
267```
268
269So that I just need to run `make` to build and `make deploy` to upload the
270new files. Watch out: if you want to reproduce this on your system, make
271sure that the user on your server has sufficient permissions to run
272that rsync command - in particular you need write permission on the
273`/var/www/htdocs` folder.
274
275If you are not familiar with the [make(1)](https://man.openbsd.org/make)
276syntax, this step is completely optional and you can simply type
277the full commands every time, or make another small script called
278`deploy.sh` and run that instead.
279
280## Follow-up?
281
282I am sure my build scripts will keep evolving over time, so at some point I
283might write a new post about the same topic. I am also probably going to write
284something about how I generate my [git page](https://git.tronto.net/) using
285[stagit](https://codemadness.org/stagit.html), if anything just to document
286my post-receive hooks. So, if you liked this post, stay tuned for more!
diff --git a/src/blog/blog.md b/src/blog/blog.md
index 7b8095b..52673bf 100644
--- a/src/blog/blog.md
+++ b/src/blog/blog.md
@@ -2,6 +2,7 @@
2 2
3[RSS Feed](feed.xml) 3[RSS Feed](feed.xml)
4 4
5* 2022-08-14 [How I update my website](2022-08-14-website)
5* 2022-07-07 [The man page reading club: shutdown(8)](2022-07-07-shutdown) 6* 2022-07-07 [The man page reading club: shutdown(8)](2022-07-07-shutdown)
6* 2022-06-12 [The UNIX shell as an IDE: look stuff up with sed](2022-06-12-shell-ide-sed) 7* 2022-06-12 [The UNIX shell as an IDE: look stuff up with sed](2022-06-12-shell-ide-sed)
7* 2022-06-08 [The man page reading club: more(1)](2022-06-08-more) 8* 2022-06-08 [The man page reading club: more(1)](2022-06-08-more)
diff --git a/src/blog/feed.xml b/src/blog/feed.xml
index a91f184..2e3382e 100644
--- a/src/blog/feed.xml
+++ b/src/blog/feed.xml
@@ -9,6 +9,13 @@ Thoughts about software, computers and whatever I feel like sharing
9</description> 9</description>
10 10
11<item> 11<item>
12<title>How I update my website</title>
13<link>https://sebastiano.tronto.net/blog/2022-08-14-website</link>
14<description>How I update my website</description>
15<pubDate>2022-08-14</pubDate>
16</item>
17
18<item>
12<title>The man page reading club: shutdown(8)</title> 19<title>The man page reading club: shutdown(8)</title>
13<link>https://sebastiano.tronto.net/blog/2022-07-07-shutdown</link> 20<link>https://sebastiano.tronto.net/blog/2022-07-07-shutdown</link>
14<description>The man page reading club: shutdown(8)</description> 21<description>The man page reading club: shutdown(8)</description>

Generated with cgit - Back to sebastiano.tronto.net