Gumulka

ein blog

Jan 19, 2020

Erste Erweiterung für FreshRSS

RSS Feed sind Sammlungen von Artikeln, welche man mit einem entsprechenden Program abrufen kann.

Es gab vor einigen Jahren mal Google News, welches das gemacht hat und ich viel genutzt habe. Allerdings hat google es geschlossen und ich bin zu Feedly gewechselt. Dort hat mich nach einiger Zeit die ständige Werbung genervt und ich wollte mehr Hoheit über meine Daten haben, also habe ich irgendwann auf einem meiner Server FreshRSS installiert und bin ganz glücklich damit.

Ich kann dort meine ganzen Feeds aggregiert lesen und alles ist gut. Bis heise vor einiger Zeit dann angefangen hat ihr Heise+ Abbonement pushen zu wollen und ich jetzt ständig Teaser für teilweise interessante Artikel in meiner Inbox habe, welche ich aber nicht lesen kann, da ich kein Heise+ Abbonement habe.

Es ergibt keinen Sinn für mich, die CT und iX haben wir auf Arbeit, die TR leiste ich mir privat, nur Heise+ ist mir die Kosten nicht Wert.

Bis jetzt habe ich aber keinen Weg gehabt Artikel einfach herauszufiltern aus meinen Listen. Klar, ich kann den Heise Feed komplett abbestellen, aber das will ich ja auch nicht, sondern nur die nicht möglichen Artikel nicht sehen.

Also habe ich angefangen mich mit den Erweiterungen von FreshRSS zu beschäftigen. Die offizielle Dokumentationswebseite ist eine Github-Page, die leider nicht sonderlich hilfreich war. Aber da es eine Github Page ist, und ich gesehen habe, dass der Link mit "01" beginnt habe ich das Repository durchsucht und die richtige Seite gefunden.

Die Dilbert Erweiterung war ein sehr guter Punkt zum starten und es generell zu verstehen. Es hat mir sehr bei der ersten Version geholfen, das Artikel als gelesen markiert, welche "heise+" im Titel haben.

Mit Hilfe der CustomJS Erweiterung habe ich verstehen können, wie die Konfiguration von Extensions funktioniert und habe dieses verwenden können um die Blacklist jetzt individuell gestalten zu können.

Mein Finaler Code ist für jeden verfügbar auf Github unter https://github.com/gumulka/freshrss-blacklist zu finden.

Ich hoffe es findet auch noch jemand anders nützlich.

Dec 26, 2019

Dec 18, 2019

Help Target im Makefile

Ich habe vor einiger Zeit angefangen Makefiles wieder verstärkt zu benutzen und lerne dabei ein paar Sachen. Man schreibt diese ja immer erst mal für sich selbst, aber teilweise auch im Team.

Gerade sitze ich an einem Projekt, wo genau das nötig ist und bin über einen Blogeintrag gestoßen, den ich äußerst hilfreich fand, aber der ein paar kleine Verbesserungen benötigt.

Sie schlagen dort vor ein Target help zu definieren:

.PHONY: help

help:
    @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

Das Ganze hat für mich nur ein paar Nachteile. Die Variable MAKEFILE_LIST enhält eine Liste von allen Makefiles und grep gibt den Dateinamen aus, wenn mehrere Dateien übergeben werden. Es fehlt hier also der -h Parameter.

Auch fände ich es schön, wenn help an sich schon dokumentiert wäre.

Und wenn es das bevorzugte Target ist, egal wo es steht, da ich das "sort" doch häufiger weg lasse.

Des weiteren arbeite ich mit Dateien, welche "." und Zahlen im Dateinamen haben können.

Meine help Target sieht also folgendermaßen aus:

# Make the Makefile self-documenting with this targets.
# Targets having a comment with double # are printed out.
.PHONY: help
help: ## Print this help message
    @grep -h -E '^[0-9a-zA-Z._-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
# Make this the default target
.DEFAULT_GOAL := help

Wenn mein Team jetzt also jetzt make ohne Parameter aufruft bekommt es eine nützliche Nachricht mit allen Parametern, welche dokumentiert sind. Und Dokumentieren tut man ja bekanntlich alles. ;-)

Nov 22, 2019

Meine git-hooks

Generelle Struktur

Da ich einige Skripte für viele bis fast alle Projekte benötigen kann, mag ich es einen globalen Ordner für git-hooks zu haben.

Wenn man die Dokumentation anguckt, dann gibt es die Möglichkeit mit

git config --global core.hooksPath ~/.githooks/

alle hooks in meinem Homeverzeichnis zu haben. Dieses hat jetzt nur ein Problem. Ich verliere all hooks, welche ich local haben möchte.

Die beste Alternative, welche ich dazu bis jetzt gefunden habe war:

Ach, dann mach in dem entsprechendem Repo einfach ein ´git config core.hooksPath .git/hooks/´

Aber das möchte ich nicht machen. Ich verliere dann meine anderen globalen Hooks, sobald ich ein Skript Lokal haben möchte.

Meine Möglichkeit das zu umgehen sieht also das folgende vor:

#!/bin/bash

for hook in applypatch-msg pre-applypatch post-applypatch pre-commit pre-merge-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-push pre-receive update post-receive post-update push-to-checkout pre-auto-gc post-rewrite sendemail-validate fsmonitor-watchman p4-pre-submit post-index-change
do
    if [ ! -e ${hook} ]; then
        echo "#!/bin/bash" > ${hook}
        echo "" >> ${hook}
        echo 'GIT_BASE_DIR=$(git rev-parse --show-toplevel)' >> ${hook}
        echo "exitcode=0" >> ${hook}
        echo "" >> ${hook}
        echo "if [ -x \${GIT_BASE_DIR}/.git/hooks/${hook} ]; then" >> ${hook}
        echo "    \$GIT_BASE_DIR/.git/hooks/${hook} \$@ || exitcode=\$?" >> ${hook}
        echo "fi" >> ${hook}
        echo "" >> ${hook}
        echo "# Please insert your checks here." >> ${hook}
        echo "" >> ${hook}
        echo "exit \${exitcode}" >> ${hook}
        chmod a+x ${hook}
    fi
done

Dieses Skript erstellt für jeden möglichen hook ein neues Skript, welches zuerst im lokalen .git/hooks Verzeichnis nachguckt ob ein Skript existiert und es ausführt.

Ein paar Sachen auf die dabei zu achten sind:

  1. Git kann Parameter übergeben (die meisten Skripte)
  2. Git kann Informationen in das Skript reinpipen (pre-push, pre-receive, post-receive)
  3. Git kann eine Ausgabe erwarten (pre-receive, update, post-receive, post-update, fsmonitor-watchman)

Meine Lösung dafür ist:

  1. $@ übergibt alle Parameter des Skriptes an das Unterskript
  2. Siehe pre-push
  3. Ich benutze sie einfach nicht. Hier sind es hauptsächlich Server-Skripte, welche bei mir nicht eingesetzt werden.

Damit habe ich jetzt globale Skripte, welche keinen Unterschied zu localen Skripten darstellen. Nur kann ich sie noch erweitern und genau das habe ich für einige auch gemacht.

commit-msg

Rechtschreibung

Meinen commit-msg hook habe ich von hier übernommen. Ich habe es nur um das grep erweitert um die Kommentare von der Prüfung auszuschließen.

ASPELL=$(which aspell)
if [ $? -ne 0 ]; then
    echo "Aspell not installed - unable to check spelling" >&2
else
    WORDS=$(grep -v -e "^#" "$1" | $ASPELL list )
fi
if [ -n "$WORDS" ]; then
    echo -e "\e[1;33mPossible spelling errors found in commit message. Use git commit --amend to change the message.\nPossible mispelled words: " $WORDS ".\e[0m" >&2
fi

Ein einfaches Skript, welches guckt, ob die Commit Message Rechtschreibfehler enthält, da sich ja doch ab und zu welche einschleichen.

pre-commit

Standartskripte

Hier benutzte ich das Beispiel-Skript, da es eine vernünftige Grundfunktionalität besitzt, welche ich eigentlich gerne überall hätte. Nur den letzten Befehl habe ich etwas überarbeitet indem ich das exec entfernt habe um danach noch weiter schreiben zu können.

if git rev-parse --verify HEAD >/dev/null 2>&1
then
    against=HEAD
else
    # Initial commit: diff against an empty tree object
    against=$(git hash-object -t tree /dev/null)
fi

# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$(git config --bool hooks.allownonascii)" != "true" ] &&
    # Note that the use of brackets around a tr range is ok here, (it's
    # even required, for portability to Solaris 10's /usr/bin/tr), since
    # the square bracket bytes happen to fall in the designated range.
    test $(git diff --cached --name-only --diff-filter=A -z $against |
      LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
    echo -e "\e[1;31mCommiting on master is not allowed!\e[0m"
    echo -e "To allow commit on master for this repo execute:\n"
    echo -e "\tgit config --local --add hooks.allownonascii true\n"
    exitcode=1
fi

# If there are whitespace errors, print the offending file names and fail.
git diff-index --check --cached $against -- || exitcode=$?

Master schützen

Es gibt allerdings noch eine kleine Erweiterung. Ich möchte nicht unbedingt auf master commiten, da ich denke ein jeder kann und sollte mit feature und development branches arbeiten, also verbiete ich es mir einfach generell.

# Check where out HEAD is at
if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
        if [ "$(git config --bool --get hooks.allowcommitonmaster)" != "true" ]; then
                echo -e "\e[1;31mCommiting on master is not allowed!\e[0m"
                echo -e "To allow commit on master for this repo execute:\n"
                echo -e "\tgit config --local --add hooks.allowcommitonmaster true\n"
                exitcode=1
        fi
fi

In manchen Repositories ist es allerdings unerlässlich und damit ich den Befehl dafür niemals vergesse schreibe ich ihn gleich in die Fehlermeldung mit rein.

Python linter

Da ich in letzter Zeit viel in Python programmiere, habe ich zuerst angefangen für viele Projekte einen Linter im CI-File zu installieren, aber ich würde den check auch gerne schon vorher haben. Also filtere ich alle python Dateien raus, welche im Commit vorkommen, und sollte dieses nicht leer sein, dann werden nur diese durch den linter durchgeschickt:

# Do a linting for all modified python files.
pythonfiles=$(git diff --name-only --cached | grep .py | xargs)
if [ "${pythonfiles}" != "" ]; then
    # color output, dont print gobal score, and use numcpu threads
    pylint --persistent=n --jobs=0 --score=n --output-format=colorized ${pythonfiles} || exitcode=$?
fi

pre-push

Skript-Probleme

Bash übergibt Standartmäßig alle nicht genutzten Parameter der Standarteingabe an das aufgerufene Skript. Was für unseren Standartworkflow genau das ist, was wir benötigen. Sollte man jedoch einmal selbst auch die Eingaben verarbeiten wollen benötigt man etwas mehr. Ich kann jetzt leider nicht die Eingaben einfach doppelt verarbeiten, sondern muss sie in einer temporären Variable speichern. Dieses sieht dann folgendermaßen aus:

#!/bin/bash

OPERANDS=$(cat)

GIT_DIR=$(git rev-parse --show-toplevel)

if [ -x ${GIT_DIR}/.git/hooks/pre-push ]; then
    echo "${OPERANDS}" | $GIT_DIR/.git/hooks/pre-push || exitcode=$?
fi

testing

Was ich nett fand war die Möglichkeit teure pre-commit skripte erst bei pre-push auszuführen. Aber das muss ich erst noch ausbauen und die Programmierumgebung/Sprache entdecken.

Irgendwas in der Richtung wird da aber noch kommen.

Server abstellen

Es gibt auf meiner Arbeit einen git Server, welcher obsolet geworden ist, da die meisten Projekte auf einen anderen umgezogen sind. Eigentlich habe ich alle Repositories umgestellt, aber falls es nicht der Fall sein sollte, dann wird hier verhindert, auf genau diesen zu puschen. (Beispiel auf den Umzug von github zu gitlab erstellt)

if [[ $2 =~ "github.com:gumulka88" ]]; then
    echo -e "\e[1;31mThou shall not push to $2!\e[0m"
    echo "Change url to the new server with:"
    newurl=$(echo "$2" | sed 's/github.com:gumulka88/gitlab.com:gumulka/g')
    echo -e "\n\tgit remote set-url $1 ${newurl}\n"
    exitcode=1
fi

README und LICENSE

Ich mache häufiger mal ein ganz kleines Repo um irgendein Skript zu speichern, welches ich ich erstellt habe, und Monate später komme ich darauf zurück und denke mir:

Was wollte ich noch einmal damit genau und wie kann ich es ändern?

oder aber:

Was waren noch mal die Vorbedingungen für diesen Code?

Hier wäre es doch super, wenn ich eine README angelegt hätte. Oder aber ich finde irgendwo im Netz ein tolles Projekt, welches aber leider nicht mehr weiter entwickelt wird und keine Lizenz hat und es rechtlich schwierig ist, das einfach so zu benutzen im Firmenumfeld. Also lass mich doch dafür sorgen, dass wenigstens ich immer eine Lizenz habe. Das muss nicht beim ersten Commit passieren, wohl aber, wenn ich es veröffentliche.

Ich habe schon die Variable GIT_BASE_DIR, welche auf mein Stammverzeichnis zeigt. Jetzt muss ich nur noch gucken, ob die Dateien existieren.

for checking in README LICENSE; do
    lower=$(echo "${checking}" | tr '[:upper:]' '[:lower:]')
    if  [ "$(ls $GIT_BASE_DIR | grep -i ${checking})" == "" ] ; then
            if [ "$(git config --bool --get hooks.pushwithout${lower})" != "true" ]; then
                    echo -e "\e[1;31mYou must have a ${checking}!\e[0m"
                    echo -e "To allow pushing without a ${checking} for this repo execute:\n"
                    echo -e "\tgit config --local --add hooks.pushwithout${lower} true\n"
                    exitcode=1
            fi
    fi
done
posted at 17:50  ·   ·  git  bash  git-hooks

Feb 19, 2019

Automatisches Erstellen

Zuerst habe ich mir überlegt wie ich es wohl schaffen könnte mit Hooks die Webseite automatisch auszuliefern, aber die Sache, dass Git mir nicht erlaubt in einem Bare repo Sachen auszuchecken und ich in einem ausgecheckten Repo nicht puschen kann macht es etwas komplizierter.

Da ich seit Monaten schon verschiedene Runner für Gitlab auf Arbeit betreibe, war es einfacher einen auf meinem Webserver zu installieren und ihm Schreibrechte auf dem Ordner mit meinem Blog zu geben.

Dazu musste ich nur das Makefile um ein Target für den Server erweitern, einen Runner installieren und ein CI Skript schreiben.

Anbei die Ergänzungen am Makefile und mein CI Skript:

PUBLISHDIR=/var/www/blog

server-publish:
    $(PELICAN) $(INPUTDIR) -o $(PUBLISHDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
publish:
    script:
        - rm -rf /var/www/blog/drafts/
        - make server-publish
Next → Page 1 of 2