diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2022-11-24 00:01:47 +0100 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2022-11-24 00:01:47 +0100 |
| commit | 1b69fbdce80f4ee2d46be63be34b4cfb4e4e11d7 (patch) | |
| tree | d587a54bfd58054a441c3e6df980ca71290aea32 /src | |
| parent | b473f7ce3895eccaf7691f6fc9296cb3c695a189 (diff) | |
| download | sebastiano.tronto.net-1b69fbdce80f4ee2d46be63be34b4cfb4e4e11d7.tar.gz sebastiano.tronto.net-1b69fbdce80f4ee2d46be63be34b4cfb4e4e11d7.zip | |
Added blog post(s)
Diffstat (limited to 'src')
| -rw-r--r-- | src/blog/2022-10-19-email-setup/email-setup.md | 201 | ||||
| -rw-r--r-- | src/blog/2022-11-23-git-host/git-host.md | 299 | ||||
| -rw-r--r-- | src/blog/blog.md | 2 | ||||
| -rw-r--r-- | src/blog/feed.xml | 14 |
4 files changed, 516 insertions, 0 deletions
diff --git a/src/blog/2022-10-19-email-setup/email-setup.md b/src/blog/2022-10-19-email-setup/email-setup.md new file mode 100644 index 0000000..849efc6 --- /dev/null +++ b/src/blog/2022-10-19-email-setup/email-setup.md | |||
| @@ -0,0 +1,201 @@ | |||
| 1 | # Keeping my email sorted (the hard way) | ||
| 2 | |||
| 3 | I have recently made some changes to my email setup. In this post I'll | ||
| 4 | explain the motivation behind these changes and what I did in practice. | ||
| 5 | |||
| 6 | ## Self-hosting? | ||
| 7 | |||
| 8 | When I got my virtual machine up and running at | ||
| 9 | [openbsd.amsterdam](https://openbsd.amsterdam/) - the one where this | ||
| 10 | website is hosted - I originally planned to host my private email | ||
| 11 | server there too. I knew this was probably a hard task, but you know, | ||
| 12 | everything is hard until you learn how to do it. | ||
| 13 | |||
| 14 | I wanted to do this for a couple of reasons. The main one was to use my | ||
| 15 | `@tronto.net` email address, but I also liked the idea of staying away | ||
| 16 | from large internet companies (my main email address was connected to my | ||
| 17 | Google account). Not that there is anything inherently wrong with using | ||
| 18 | services from this big companies, but I like the idea of not being too | ||
| 19 | dependent on them. | ||
| 20 | |||
| 21 | After reading | ||
| 22 | [a nice tutorial at poolp.org](https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/) | ||
| 23 | I was a bit discouraged. The guide was well-written, all the steps seemed | ||
| 24 | doable if taken one by one, and I was happy to have dug into this topic | ||
| 25 | because I learned a lot. However, an email server apparently consists of | ||
| 26 | a lot of moving pieces: an smtp server, spam filter, DNS, DKIM... it is | ||
| 27 | a lot to keep track of. Even assuming that I would be able to set this | ||
| 28 | thing up AND to keep in mind what each of these pieces does, as soon as a | ||
| 29 | problem of any kind arises - config-breaking updates? domain registration | ||
| 30 | expiring? me messing up with my VM and making it unreachable? - I knew I | ||
| 31 | had to be one to fix the mistake. And I cannot afford to be immediately | ||
| 32 | available whenever something bad happens. Sometimes I might just have a | ||
| 33 | full week were I don't have time to fiddle around with smtpd and whatnot, | ||
| 34 | and I can't afford being unreachable via email for a week. | ||
| 35 | |||
| 36 | ## My old setup (until September 2022) | ||
| 37 | |||
| 38 | Having abandoned the idea of self-hosting, I looked for alternatives. I | ||
| 39 | figured that if my goals were just to use my own domain and stay away | ||
| 40 | from Google, I could sign up for a smaller email provider that offers | ||
| 41 | custom domains. It turns out there are a lot of them. After some careful | ||
| 42 | considerations I decided to go with [mailbox.org](https://mailbox.org). I | ||
| 43 | like their transparency and privacy focus and the fact that they are | ||
| 44 | based in the EU. I pay 3€ per month (the 1€ tier does not offer | ||
| 45 | custom domains) and I am happy with their service. | ||
| 46 | |||
| 47 | Setting up the server side was quite simle. Using custom domains | ||
| 48 | requires a tiny bit of work, but it was all well explained in the | ||
| 49 | [FAQs](https://kb.mailbox.org/en/private/custom-domains). | ||
| 50 | |||
| 51 | On my local machine I used (and still use) the amazing | ||
| 52 | [mblaze](https://github.com/leahneukirchen/mblaze), which is essentially | ||
| 53 | [MH](https://en.wikipedia.org/wiki/MH_Message_Handling_System) | ||
| 54 | for [Maildir](https://en.wikipedia.org/wiki/Maildir) folders. | ||
| 55 | In practice, mblaze is a set of commands to manage emails directly | ||
| 56 | from the command line, without using a graphical environment or a | ||
| 57 | [TUI](https://en.wikipedia.org/wiki/Text-based_user_interface) like | ||
| 58 | [Mutt](https://en.wikipedia.org/wiki/Mutt_(email_client)). This system | ||
| 59 | is incredibly flexible, check it out if you don't know it! | ||
| 60 | |||
| 61 | Being just a mail user agent, mblaze cannot retrieve or send | ||
| 62 | email. These tasks can be accomplished by other small pieces of | ||
| 63 | software: I used [msmtp](https://marlam.de/msmtp) for sending | ||
| 64 | email and [mpop](https://marlam.de/mpop) for downloading it | ||
| 65 | from mailbox.org's server. As the name suggests, mpop uses the | ||
| 66 | [POP3](https://en.wikipedia.org/wiki/Post_Office_Protocol) | ||
| 67 | protocol instead of the more common | ||
| 68 | [IMAP](https://en.wikipedia.org/wiki/Internet_Message_Access_Protocol). | ||
| 69 | The main difference is that POP3 simply retrieves your email, while | ||
| 70 | IMAP keeps the server and client folders synchronized. There are many | ||
| 71 | advantages and disadvantages to this choice, I won't go into detail on | ||
| 72 | them in this post. | ||
| 73 | |||
| 74 | As for my other devices, my local mailfolder is kept in sync with my | ||
| 75 | server using [syncthing](https://syncthing.net). I also use an amail | ||
| 76 | client on my phone with IMAP, connected directly to the mail server. | ||
| 77 | |||
| 78 | ## Nitpicking | ||
| 79 | |||
| 80 | Since I am subscribed to a couple of high-traffic mailing lists that | ||
| 81 | I read just for curiosity, it is necessary for me to have an easy way | ||
| 82 | to download and view regular emails separately from that coming from | ||
| 83 | mailing lists. | ||
| 84 | |||
| 85 | This was kinda easy to set up with mpop's filters, but my configuration | ||
| 86 | was a bit of a hack. One disadvantage of this soution was that it | ||
| 87 | only solved the problem on my laptop(s). On my webmail and on my phone, | ||
| 88 | my inbox was a complete mess of mailing lists, newsletter and a few | ||
| 89 | important emails. | ||
| 90 | |||
| 91 | After thinking about it for a while I figured that an elegant solution | ||
| 92 | would be to set up alternative email addresses for receiving mailing | ||
| 93 | list emails, like `list@tronto.net`. Then I would manage those different | ||
| 94 | mailboxes separately. | ||
| 95 | |||
| 96 | Setting the aliases up on mailbox.org was easy, but unfortunately all my | ||
| 97 | `@tronto.net` address used the same inbox, so I did not solve any problem | ||
| 98 | at all. I could add some sub-folders and set up filters so that incoming | ||
| 99 | mail gets sorted out, but the app on my phone could not read sub-folders | ||
| 100 | and mailbox did not allow top-level folders (or I could not find a way to | ||
| 101 | create them). Besides, tinkering with IMAP folders was not something | ||
| 102 | that I found particularly exciting. | ||
| 103 | |||
| 104 | But there was another solution... | ||
| 105 | |||
| 106 | ## My current setup (since September 2022) | ||
| 107 | |||
| 108 | I decided to try and redirect the mailing list emails to my personal | ||
| 109 | server. Configuring OpenBSD's smtp to receive emails from one specific | ||
| 110 | outside source (my mailbox.org account) and sort them into some local | ||
| 111 | folders is order of magnitudes easier than setting up a full-fledged | ||
| 112 | email server. No problems with DKIM, no incoming spam, no nothing. | ||
| 113 | |||
| 114 | It took me a few hours to figure our how to do this, but in the | ||
| 115 | end it is just a matter of configuring a few filters on mailbox.org | ||
| 116 | and adding a couple of lines to `/etc/mail/stmp.conf`. | ||
| 117 | |||
| 118 | ### mailbox.org filters | ||
| 119 | |||
| 120 | On my mailbox.org webmail I simply set up a filter to redirect any email | ||
| 121 | sent to `list@example.com` (a made-up name for the mailing list I am | ||
| 122 | subscribed to) to my private server. No copy of these emails is kept on | ||
| 123 | the server, so they don't clutter my normal (IMAP) inbox. I risk missing | ||
| 124 | a few of these emails if my server goes down, but it is a public mailing | ||
| 125 | list and I can always check the archives online. | ||
| 126 | |||
| 127 | I could not just send these emails to `something@tronto.net`, otherwise | ||
| 128 | they would simply be taken care of by mailbox - the MX records for my | ||
| 129 | domain point to their servers. But it turns out you can send mail to | ||
| 130 | a server using its IP address, as long as the server is configured to | ||
| 131 | accept such mail. So I set up the redirects to `list@[46.23.91.214]` - | ||
| 132 | where `46.23.91.214` is the IP address of my server. | ||
| 133 | |||
| 134 | ### smtpd.conf | ||
| 135 | |||
| 136 | The second step is configuring smtpd, OpenBSD's default mail server | ||
| 137 | daemon, to deal with incoming email. | ||
| 138 | |||
| 139 | First of all we need to list the virtual user `list` in | ||
| 140 | `/etc/mail/aliases` so that any mail sent to it is interpreted as being | ||
| 141 | sent to my regular user. | ||
| 142 | |||
| 143 | ``` | ||
| 144 | # cat 'list: sebastiano' >> /etc/mail/aliases | ||
| 145 | ``` | ||
| 146 | |||
| 147 | Then we have to change the line `listen on lo0` to `listen on all` | ||
| 148 | in `/etc/smtp.conf`. | ||
| 149 | |||
| 150 | Then we need to add an `action` and a `match` lines to the same file: | ||
| 151 | |||
| 152 | ``` | ||
| 153 | # cat << EOF >> /etc/mail/smtpd.conf | ||
| 154 | > action "list" maildir "~/mail/list" alias <aliases> | ||
| 155 | > match from any for rcpt-to "list@[46.23.91.214]" action "list" | ||
| 156 | > EOF | ||
| 157 | ``` | ||
| 158 | |||
| 159 | And finally restart smtpd with `rcctl restart smtpd`. | ||
| 160 | |||
| 161 | This does the trick: now all email I receive from the `list@example.com` | ||
| 162 | mailing list is redirected by my mailbox account to my private server, | ||
| 163 | where smtpd takes care of sending it to the mail directory `~/mail/list`. | ||
| 164 | |||
| 165 | ### No mpop needed | ||
| 166 | |||
| 167 | Once the mail is delivered to `~/mail/list`, I can get it from there | ||
| 168 | to my laptop in any way I like - for example using syncthing, like I | ||
| 169 | do for all my important files. In this way the mailing list emails are | ||
| 170 | regularly downloaded and kept in sync, and I don't need to use mpop to | ||
| 171 | retrieve them. | ||
| 172 | |||
| 173 | This is quite convenient, one less piece of software to keep track of! | ||
| 174 | In fact, I can do the same for all other email I receive. I just need | ||
| 175 | to set up the appropriate rules on mailbox: this time I want the mail | ||
| 176 | to be sent to `sebastiano@[46.23.91.214]` and *a copy to be kept on the | ||
| 177 | mailbox.org server*, so that I can easily access it from my phone's app as | ||
| 178 | well. Then I add two slightly different lines to `/etc/mail/smtpd.conf`: | ||
| 179 | |||
| 180 | ``` | ||
| 181 | # cat << EOF >> /etc/mail/smtpd.conf | ||
| 182 | > action "seb" maildir "~/mail/inbox" user sebastiano | ||
| 183 | > match from any for rcpt-to "sebastiano@[46.23.91.214]" action "seb" | ||
| 184 | > EOF | ||
| 185 | ``` | ||
| 186 | |||
| 187 | And the new setup is ready! | ||
| 188 | |||
| 189 | ### Sending email | ||
| 190 | |||
| 191 | I did not change the way I send email: I still use msmtp. | ||
| 192 | |||
| 193 | ## Happy now? | ||
| 194 | |||
| 195 | Yes, this new setup works and I am always happy when things work. | ||
| 196 | Of course, one might make the case that things worked before as well... | ||
| 197 | |||
| 198 | I am happy that I could work my way around a basic smtpd configuration. | ||
| 199 | Besides being useful knowledge on its own, it may make a second attempt | ||
| 200 | at self-hosting my email less daunting. I don't know if I am ever going | ||
| 201 | to try that, though. | ||
diff --git a/src/blog/2022-11-23-git-host/git-host.md b/src/blog/2022-11-23-git-host/git-host.md new file mode 100644 index 0000000..cc9fc27 --- /dev/null +++ b/src/blog/2022-11-23-git-host/git-host.md | |||
| @@ -0,0 +1,299 @@ | |||
| 1 | # Self-hosted git pages with stagit (featuring ed, the standard editor) | ||
| 2 | |||
| 3 | This is a follow-up to my earlier blog entry | ||
| 4 | [How I update my website](../2022-08-14-website). | ||
| 5 | |||
| 6 | If you work on one or more personal software projects as a hobby, | ||
| 7 | chances are you are using `git`. To publish your project online | ||
| 8 | you may be using a website like GitHub, or perhaps a more | ||
| 9 | open source friendly alternative such as | ||
| 10 | [GitLab](https://about.gitlab.com/) or [sourcehut](https://sourcehut.org/). | ||
| 11 | |||
| 12 | But have you considered hosting your repositories, and serving them | ||
| 13 | via web pages, on your personal server? In this post I am going to show | ||
| 14 | you how I do it, in the usual minimalist and | ||
| 15 | not-using-what-I-do-not-understand style. | ||
| 16 | |||
| 17 | You can see the final result on my [git pages](https://git.tronto.net). | ||
| 18 | The scripts and other files I use to set this up are accessible | ||
| 19 | [here](https://git.tronto.net/git-hooks). | ||
| 20 | |||
| 21 | ## Hosting git repositories on your own server | ||
| 22 | |||
| 23 | This step is quite simple, and you can just follow | ||
| 24 | [Roman Zolotarev's tutorial](https://rgz.ee/git.html) like I did - adapting | ||
| 25 | the first few steps to your OS if you are not running OpenBSD. | ||
| 26 | |||
| 27 | To sum it up, you need to: | ||
| 28 | |||
| 29 | 1. Create a dedicate `git` account on your server (optional, if you know | ||
| 30 | what you are doing). | ||
| 31 | |||
| 32 | 2. Add your public SSH key to the `~/.ssh/authorized_keys` file of your newly | ||
| 33 | created remote account. | ||
| 34 | |||
| 35 | 3. Initialize a git repository on your server with `git init REPOSITORY`. | ||
| 36 | |||
| 37 | 4. Clone it via SSH with `git clone git@SERVER:REPOSITORY`. | ||
| 38 | |||
| 39 | And you are done! If you want to use multiple remotes, for example your private | ||
| 40 | server and GitHub, you can do so by adding a push-only URL with | ||
| 41 | `git remote set-url --add --push origin URL`. But don't trust me on this | ||
| 42 | exact command, I always have to look it up | ||
| 43 | - you should do the same before running it. | ||
| 44 | |||
| 45 | Now your repositories are online, but how can you make them browsable via web? | ||
| 46 | |||
| 47 | ## stagit | ||
| 48 | |||
| 49 | The tool I use to serve my git repositories as static web pages is | ||
| 50 | [stagit](https://codemadness.org/stagit.html). It is very easy to describe what | ||
| 51 | stagit does: running it on a git reporitory produces some directories with | ||
| 52 | a bunch of html files that you can simply move to your www hosting directory. | ||
| 53 | |||
| 54 | After generating the pages you can personalize them by copying your logo, | ||
| 55 | [favicon](https://en.wikipedia.org/wiki/Favicon) or CSS style sheet. You can | ||
| 56 | use `stagit-index` to generate | ||
| 57 | [an index page for your repositories](https://git.tronto.net/). Since everything | ||
| 58 | consists of html files, you can simply edit them to personalize your git pages | ||
| 59 | even further - and below you'll see some examples. | ||
| 60 | |||
| 61 | But you definitely do not want to do this by hand every time you push a commit. | ||
| 62 | Since the pages stagit generates are *static*, they do not update | ||
| 63 | automatically: you'll have to run stagit again every time. You can automate | ||
| 64 | this for example by running stagit periodically with cron, but there is an | ||
| 65 | easier way: | ||
| 66 | [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). | ||
| 67 | |||
| 68 | ## Git hooks | ||
| 69 | |||
| 70 | By saving suitably named executable files inside your project's | ||
| 71 | `.git/hooks` directory you can automate any process you want during | ||
| 72 | certain stages of your git workflow. For example you can use a `pre-commit` | ||
| 73 | script to run commands before you commit changes, or a `pre-push` script | ||
| 74 | to do something before pushing a commit. | ||
| 75 | |||
| 76 | The hooks are divided in client-side and server-side. We are interested in | ||
| 77 | the server-side `post-receive` hook, which is executed on the remote every | ||
| 78 | time a commit is received. This is the last ingredient we need for our setup: | ||
| 79 | a simple `post-receive` hook that runs stagit and copies the files it | ||
| 80 | generates to the appropriate folder will do the trick. | ||
| 81 | |||
| 82 | ## My setup | ||
| 83 | |||
| 84 | Throughout the rest of the post I will use the following variables, to be | ||
| 85 | set at the beginning of the script: | ||
| 86 | |||
| 87 | ``` | ||
| 88 | yourname="Sebastiano Tronto" # Author's name | ||
| 89 | repo="$PWD" # The full path of the repository | ||
| 90 | name="$(basename $repo .git)" # The name of the repository | ||
| 91 | baseurl="https://git.tronto.net" # The base URL for the repository | ||
| 92 | basedir="/var/www/htdocs/git.tronto.net" # The base directory for www files | ||
| 93 | htdir="$basedir/$name" # The www directory for the repository | ||
| 94 | ``` | ||
| 95 | |||
| 96 | ### Basic stagit usage | ||
| 97 | |||
| 98 | The first thing we want to do is to set up some basic information in the | ||
| 99 | `owner` and `url` files that stagit is going to use. The hook is run in the | ||
| 100 | repository's directory, so it is not necessary to specify a full path: | ||
| 101 | |||
| 102 | ``` | ||
| 103 | echo "$yourname" > owner | ||
| 104 | echo "$baseurl/$name" > url | ||
| 105 | ``` | ||
| 106 | |||
| 107 | Next we prepare the target directory by removing old files and creating | ||
| 108 | it if necessary: | ||
| 109 | |||
| 110 | ``` | ||
| 111 | rm -rf "$htdir" | ||
| 112 | mkdir -p "$basedir" | ||
| 113 | ``` | ||
| 114 | |||
| 115 | To make the repository clonable by anyone from the same URL used to | ||
| 116 | view it, we need to copy the whole directory to the | ||
| 117 | www directory we have just created: | ||
| 118 | |||
| 119 | ``` | ||
| 120 | cp -r "$repo" "$htdir" | ||
| 121 | ``` | ||
| 122 | |||
| 123 | And finally we can run stagit: | ||
| 124 | |||
| 125 | ``` | ||
| 126 | cd "$htdir" | ||
| 127 | stagit -l 100 "$repo" | ||
| 128 | ``` | ||
| 129 | |||
| 130 | The `-l` option is used to specify how many commits should be visibile | ||
| 131 | in the log page. | ||
| 132 | |||
| 133 | For some basic personalization we can choose a different default page (index | ||
| 134 | file). I like to have the file list: | ||
| 135 | |||
| 136 | ``` | ||
| 137 | cp "$htdir/files.html" "$htdir/index.html" | ||
| 138 | ``` | ||
| 139 | |||
| 140 | And we can use our css style sheet, logo and icon: | ||
| 141 | |||
| 142 | ``` | ||
| 143 | cp $filesdir/favicon.png ./ | ||
| 144 | cp $filesdir/logo.png ./ | ||
| 145 | cp $filesdir/style.css ./ | ||
| 146 | ``` | ||
| 147 | |||
| 148 | ### Bells and whistles | ||
| 149 | |||
| 150 | I like stagit's simplicity, but there are a couple of things that I want to | ||
| 151 | add or change: | ||
| 152 | |||
| 153 | * I would like every page to show a simple footer at the bottom of | ||
| 154 | each page. | ||
| 155 | * I would like to have a download button so that people who don't use git | ||
| 156 | can still download my files. This makes sense especially for those | ||
| 157 | repos that are mostly documents, such as my | ||
| 158 | [lecture notes](https://git.tronto.net/mathsoftware) or my | ||
| 159 | [FMC tutorial](https://git.tronto.net/fmctutorial). | ||
| 160 | * I would like to convert README.md files to html. | ||
| 161 | |||
| 162 | If I were calling stagit by hand after each `git push`, I | ||
| 163 | could simply make these changes with a text editor. But I want to automate | ||
| 164 | this! How can we edit files in a shell script? | ||
| 165 | |||
| 166 | Enter `ed`, [the standard editor](https://www.gnu.org/fun/jokes/ed-msg.html). | ||
| 167 | `ed` is a [line text editor](https://en.wikipedia.org/wiki/Line_editor) | ||
| 168 | initially released with UNIX Version 1. I am going to talk about it more | ||
| 169 | extensively in the next episode of my | ||
| 170 | [man page reading club](../2022-05-29-man/) | ||
| 171 | series. Without going into detail, `ed` does not show you the text you | ||
| 172 | are editing in a 2-dimensional windows: instead, it offers you a command | ||
| 173 | line prompt that you can use to run editing commands, such as `a` to add | ||
| 174 | text or `p` to print one or more lines of the file. | ||
| 175 | |||
| 176 | This might seems like a totally cumbersome way of editing a file, but | ||
| 177 | there is one nice side-effect: `ed` is completely scriptable. This means | ||
| 178 | that if you know exactly what the file you want to edit looks like, | ||
| 179 | you can write the commands you want to run in advance and feed them to | ||
| 180 | the editor via standard input, instead of typing them interactively. | ||
| 181 | This is exactly what we want to do! | ||
| 182 | |||
| 183 | Going back to my stagit setup, say we have a file `bottom.html` that | ||
| 184 | looks like this: | ||
| 185 | |||
| 186 | ``` | ||
| 187 | <hr class="line"> | ||
| 188 | <footer> <table> | ||
| 189 | <tr> <td class="contact"> | ||
| 190 | Back to <a href="https://sebastiano.tronto.net"> sebastiano.tronto.net </a> | ||
| 191 | </td> | ||
| 192 | <td class="hosted"> | ||
| 193 | Generated with <a href="https://codemadness.org/stagit.html">stagit</a> | ||
| 194 | </td> </tr> | ||
| 195 | </table> </footer> | ||
| 196 | ``` | ||
| 197 | |||
| 198 | and we want to insert its content in the file `file.html`, before | ||
| 199 | the line that contains the closing tag `</body>`. We can use the | ||
| 200 | following one-liner: | ||
| 201 | |||
| 202 | ``` | ||
| 203 | printf '%s\n' "/<\/body>" i "$(cat bottom.html)" . w | ed -s file.html | ||
| 204 | ``` | ||
| 205 | |||
| 206 | Here the `printf` command is used to feed the tokens `/<\/body>`, `i`, | ||
| 207 | `$(cat bottom.html)`, `.` and `w` to `ed`. These are going to | ||
| 208 | be interpreted as: "search for the closing tag `</body>`; | ||
| 209 | insert the following text until you encounter a single dot on a line: | ||
| 210 | [contents of the file `bottom.html`] single dot; save." | ||
| 211 | If this seems obscure, I suggest you read | ||
| 212 | [`ed`'s manual page](https://man.openbsd.org/OpenBSD-7.2/ed), or wait | ||
| 213 | for my next blog post! | ||
| 214 | |||
| 215 | The command for adding the download button is similar, after we | ||
| 216 | generate a zip archive of the repository using `git archive`: | ||
| 217 | |||
| 218 | ``` | ||
| 219 | git archive HEAD -o "$basedir/$name.zip" | ||
| 220 | printf '%s\n' \ | ||
| 221 | "/log\.html\">Log<\/a>" i \ | ||
| 222 | "<a href=\"$baseurl/$name.zip\">Download</a> |" . w \ | ||
| 223 | | ed -s file.html | ||
| 224 | ``` | ||
| 225 | |||
| 226 | Here I am using backlashes to ignore the newline character, so that | ||
| 227 | I can use more lines for readability. | ||
| 228 | |||
| 229 | The two code snippets above have to be run for every html file generated | ||
| 230 | by stagit. To loop over all these files, you can use `find`: | ||
| 231 | |||
| 232 | ``` | ||
| 233 | for f in $(find "$htdir" -name "*.html"); do | ||
| 234 | [stuff...] | ||
| 235 | done | ||
| 236 | ``` | ||
| 237 | |||
| 238 | The command to turn README.md files into a formatted html page is a bit | ||
| 239 | more complicated, but I will try to keep the explanation short, since | ||
| 240 | this post is already quite long. Feel free to send me an email if you | ||
| 241 | have questions! | ||
| 242 | |||
| 243 | To have an idea of what the README.md.html file generated by | ||
| 244 | stagit looks like, you can check out the html of | ||
| 245 | [this page](https://codemadness.org/git/stagit/file/README.html), | ||
| 246 | for example (right click and "View page source" or something similar in | ||
| 247 | most browsers, or `curl [URL]` if you are cool). | ||
| 248 | |||
| 249 | First, since I am using bare git repositories, I need to actually "create" | ||
| 250 | the original README.md file - instead of using its rendered-as-plain-text | ||
| 251 | html version generated by stagit - using `git show`. Then we need to | ||
| 252 | remove from README.md.html all the lines that | ||
| 253 | are part of the code listing, i.e. all those that contain a `class="line"` | ||
| 254 | string. The `ed` command to do this is `g/class=\"line\"/d`. Then we | ||
| 255 | need to remove a couple more lines and finally we can insert the result | ||
| 256 | of the command `lowdown file/README.md`, which converts the markdown | ||
| 257 | file to html, into the correct place. The final result is: | ||
| 258 | |||
| 259 | ``` | ||
| 260 | git show master:README.md > file/README.md | ||
| 261 | printf '%s\n' \ | ||
| 262 | g/class=\"line\"/d \ | ||
| 263 | "/<pre id=\"blob\">" d d i "$(lowdown file/README.md)" . w \ | ||
| 264 | | ed -s file/README.md.html > /dev/null | ||
| 265 | ``` | ||
| 266 | |||
| 267 | ### stagit-index | ||
| 268 | |||
| 269 | Just a quick mention to how I use stagit-index, the command used to | ||
| 270 | generate the index page. | ||
| 271 | The only change I make from the default configuration is to change | ||
| 272 | the links to each repository to point to the file list instead | ||
| 273 | of the log page. stagit-index writes its result to standard output, so | ||
| 274 | I can simply use `sed`: | ||
| 275 | |||
| 276 | ``` | ||
| 277 | stagit-index /home/git/*.git | sed 's|/log\.html||g' > "$basedir/index.html" | ||
| 278 | ``` | ||
| 279 | |||
| 280 | And that's it. Well, I also copy the style files and add a bottom bar, | ||
| 281 | and change the title from a `<span class="desc">` to an `<h1>` element, | ||
| 282 | again using `ed`. If you want to see the details you can check them out | ||
| 283 | [here](https://git.tronto.net/git-hooks/file/post-receive-stagit.html). | ||
| 284 | |||
| 285 | ## Conclusions | ||
| 286 | |||
| 287 | stagit is the perfect minimalist tool to publish your git repository | ||
| 288 | with a simple, static web interface. It requires nothing more than | ||
| 289 | an http server capable of serving html files. Static files are also | ||
| 290 | very simple to customize and tune to your needs. | ||
| 291 | |||
| 292 | I have wanted to make this post for quite some time now, mainly | ||
| 293 | as an excuse to clean up and document my scripts. I finally had some | ||
| 294 | time to work on this - even if scattered around multiple days. | ||
| 295 | |||
| 296 | As always, I have tried but failed to keep my post short - I am too | ||
| 297 | eager to explain everything I know as clearly as possbile! | ||
| 298 | I hope you enjoyed or found it useful. If you have questions or comments, | ||
| 299 | feel free to send me an [email](mailto:sebastiano@tronto.net). | ||
diff --git a/src/blog/blog.md b/src/blog/blog.md index 8399626..3ffa250 100644 --- a/src/blog/blog.md +++ b/src/blog/blog.md | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | [RSS Feed](feed.xml) | 3 | [RSS Feed](feed.xml) |
| 4 | 4 | ||
| 5 | * 2022-11-23 [Self-hosted git pages with stagit (featuring ed, the standard editor)](2022-11-23-git-host) | ||
| 6 | * 2022-10-19 [Keeping my email sorted (the hard way)](2022-10-19-email-setup) | ||
| 5 | * 2022-10-01 [The man page reading club: tetris(6)](2022-10-01-tetris) | 7 | * 2022-10-01 [The man page reading club: tetris(6)](2022-10-01-tetris) |
| 6 | * 2022-09-20 [The man page reading club: sh(1) - part 2: commands and builtins](2022-09-20-sh-2) | 8 | * 2022-09-20 [The man page reading club: sh(1) - part 2: commands and builtins](2022-09-20-sh-2) |
| 7 | * 2022-09-13 [The man page reading club: sh(1) - part 1: shell grammar](2022-09-13-sh-1) | 9 | * 2022-09-13 [The man page reading club: sh(1) - part 1: shell grammar](2022-09-13-sh-1) |
diff --git a/src/blog/feed.xml b/src/blog/feed.xml index 1cf4313..0efe9ec 100644 --- a/src/blog/feed.xml +++ b/src/blog/feed.xml | |||
| @@ -9,6 +9,20 @@ Thoughts about software, computers and whatever I feel like sharing | |||
| 9 | </description> | 9 | </description> |
| 10 | 10 | ||
| 11 | <item> | 11 | <item> |
| 12 | <title>Self-hosted git pages with stagit (featuring ed, the standard editor)</title> | ||
| 13 | <link>https://sebastiano.tronto.net/blog/2022-11-23-git-host</link> | ||
| 14 | <description>Self-hosted git pages with stagit (featuring ed, the standard editor)</description> | ||
| 15 | <pubDate>2022-11-23</pubDate> | ||
| 16 | </item> | ||
| 17 | |||
| 18 | <item> | ||
| 19 | <title>Keeping my email sorted (the hard way)</title> | ||
| 20 | <link>https://sebastiano.tronto.net/blog/2022-10-19-email-setup</link> | ||
| 21 | <description>Keeping my email sorted (the hard way)</description> | ||
| 22 | <pubDate>2022-10-19</pubDate> | ||
| 23 | </item> | ||
| 24 | |||
| 25 | <item> | ||
| 12 | <title>The man page reading club: tetris(6)</title> | 26 | <title>The man page reading club: tetris(6)</title> |
| 13 | <link>https://sebastiano.tronto.net/blog/2022-10-01-tetris</link> | 27 | <link>https://sebastiano.tronto.net/blog/2022-10-01-tetris</link> |
| 14 | <description>The man page reading club: tetris(6)</description> | 28 | <description>The man page reading club: tetris(6)</description> |
