blog

Categories     Timeline     RSS

Getting rid of cgit

I replaced cgit on my git server with a more minimal web representation. I think that people are, if at all, either interested in the current content of master/HEAD or want to clone the repo anyway.

Dumping master/HEAD

#!/bin/sh

set -eu

DIR="/var/www/git-dump/$1"

files=`git ls-tree --full-tree -r --name-only HEAD`

rm -rf "$DIR"

echo "$files" | while IFS=$'\n' read -r f; do
  subdir=`dirname $f`
  fulldir="$DIR/$subdir"
  mkdir -p "$fulldir"
  fullpath="$DIR/$f"
  git show HEAD:"$f" > "$fullpath"
  if file "$fullpath" | grep -q "text"; then
    :
  else
    echo "Binary file" > "$fullpath"
  fi
done

This script is called from post-receive hooks with the repo name as argument.

Public clone

The git-daemon allows public cloning via the git protocol on port 9418. Repositories need an empty git-daemon-export-ok file. I also set –base-path to the git repo root folder, so that stuff viewed in e.g. https://git.fireandbrimst.one/simpleserver/ can be cloned with git clone git://git.fireandbrimst.one/simpleserver.

Nginx file type

The git dump has its own nginx server configuration. Inside I made sure to only serve files as text/plain:

server {
  types { }
  default_type text/plain;
  listen 80;
  ...
  autoindex on;
}

Austrian corona stamp

Austrian corona stamp

… in my local (German) post office, asking about corona stamps earned me a blank stare.

Motivation is overrated and so is discipline

Anyway, I wanted to talk about being highly motivated and New Year’s resolutions. Do yourself a favor and forget about both. Statistically speaking, the lifetime of your resolutions is coming to a middle anyway, even if it were a normal year. If you’re immensely stubborn, you may get eight good weeks. Or ten. On rare occasions even half a year. But you will fail. You will have watched all the cheesy MotivationTube videos you can stomach and end up at DisciplineTube, gorging on the lessons of retired marines learned in their reductionist and ironically socialist bubble. Ah-HA, so it’s all about discipline, not motivation. But when you listen closely, it isn’t. “I do X every day at T” is not discipline, forcing yourself to do something through sheer will. It’s just a habit.

Maybe I’m a bit slow, but this seemed like a valuable insight to me. If you want to do something, don’t rely on either motivation or discipline. Both will run out. Instead, put yourself into a position to build a habit, so you don’t have to think about doing or not doing X. Have trouble getting out of bed in the morning? Always get up at the same time without exception, weekends included. Want to exercise more? Pick Mo-We-Fr and always work out at the same time. Never re-schedule. Always keep in mind, that any deviation is undoing the habit. Using discipline would be painful, why would you want to?

Watch website changes with RSS

I use the Go program below to get notifications in my RSS reader when websites change that don’t offer RSS feeds themselves. For each website you would create a new command in main(), choose a shortname, enter the URL and enter a HTML node selector for the part you are interested in (thus also excluding surrounding stuff that might be dynamically created on each visit). You would then call this program with “go run webwatcher SHORTNAME” in your RSS reader.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	. "git.fireandbrimst.one/aw/goutil/html"
	"git.fireandbrimst.one/aw/goutil/misc"
	xnetHtml "golang.org/x/net/html"
	"io/ioutil"
	"os"
	"path"
	"text/template"
	"time"
)

const (
	DL_LIMIT     = 15 * 1024 * 1024
	CACHE_FOLDER = "cache"
)

const RSS_TEMPLATE string = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title><![CDATA[ {{.Shortname}} ]]></title>
<link><![CDATA[ {{.URL}} ]]></link>
<description><![CDATA[ {{.Shortname}} ]]></description>

    <item>
      <title><![CDATA[ {{.URL}} ]]></title>
      <content:encoded><![CDATA[ {{.LastContent}} ]]></content:encoded>
      <guid><![CDATA[ {{.URL}}/{{.LastModified.Format "20060102-150405"}} ]]></guid>
      <link><![CDATA[ {{.URL}} ]]></link>
      <pubDate>{{.LastModified.Format "Mon, 02 Jan 2006 15:04:05 -0700"}}</pubDate>
    </item>

</channel>
</rss>
`

func optPanic(err error) {
	if err != nil {
		panic(err)
	}
}

type command struct {
	shortname string
	URL       string
	selector  func(n *HtmlNode) bool
}

func (c *command) filename() string {
	return path.Join(CACHE_FOLDER, c.shortname)
}

func (c *command) getContent() string {
	b, err := misc.DownloadAll(c.URL, DL_LIMIT)
	optPanic(err)
	tmpdoc, err := xnetHtml.Parse(bytes.NewReader(b))
	optPanic(err)
	doc := (*HtmlNode)(tmpdoc)
	n := doc.Find(c.selector)
	var buf bytes.Buffer
	xnetHtml.Render(&buf, (*xnetHtml.Node)(n))
	return buf.String()
}

func unmarshalHPObject(filename string) HP {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		bytes = []byte{}
	}
	var hpObject HP
	err = json.Unmarshal(bytes, &hpObject)
	if err != nil {
		hpObject = HP{}
	}
	return hpObject
}

func marshalHPObject(filename string, hp HP) {
	bytes, err := json.MarshalIndent(hp, "", "  ")
	optPanic(err)
	err = ioutil.WriteFile(filename, bytes, 0644)
	optPanic(err)
}

func (c *command) genRSS() {
	content := c.getContent()
	hpObject := unmarshalHPObject(c.filename())
	hpObject.Shortname = c.shortname
	hpObject.URL = c.URL
	if content != hpObject.LastContent {
		hpObject.LastContent = content
		hpObject.LastModified = time.Now()
	}
	err := rssTemplate.Execute(os.Stdout, hpObject)
	optPanic(err)
	marshalHPObject(c.filename(), hpObject)
}

type HP struct {
	Shortname    string
	URL          string
	LastContent  string
	LastModified time.Time
}

var rssTemplate *template.Template

func main() {
	rssTemplate = template.Must(template.New("rss").Parse(RSS_TEMPLATE))
	os.Mkdir(CACHE_FOLDER, 0755)

	commands := []command{
		command{"stilldrinking", "https://www.stilldrinking.org/", IsTag("div").And(HasID("cont"))},
	}

	for _, command := range commands {
		if command.shortname == os.Args[1] {
			command.genRSS()
			os.Exit(0)
		}
	}
	fmt.Fprintln(os.Stderr, "unknown command", os.Args[1])
	os.Exit(-1)
}

Inline style block with Content Security Policy

To my surprise, it is possible to serve inline style blocks with Content Security Policy enabled:

< Older

Newer >