Damian Brunold

Automatisches git update

2012-02-16 14:10 Linux

Ich habe ein git repository das unter anderem eine Website enthält. Davon gibt es auf dem Webserver ein geklontes repository, das in Apache eingebunden ist, sodass mit einem einfachen git pull die Website aktualisiert werden kann.

Nun wollte ich das einen Schritt vereinfachen. Ich wollte nur schon durch git push ins zentrale Repository die Website aktualisieren. Für solche Sachen gibt es hooks, in diesem Fall den post-receive Hook (früher post-update). Mein Ansatz war somit, in diesem Hook das

cd /path/to/web/site/repo
git pull

zu schreiben. Leider klappte dies nicht. Es stellte sich heraus, dass die Environmentvariable GIT_DIR gesetzt war und somit das cd keinen Einfluss hatte. Die Lösung ist stattdessen

cd /path/to/web/site/repo
env -i git pull

zu schreiben. Das klappt tadellos.

Bash-Prompt mit Git Branch Info

2012-02-13 09:56 Linux, Programmieren

Ich habe nun meinen Bash-Prompt so angepasst, dass ich sehe auf welchem git branch ich bin und was sein Zustand ist. Dazu habe ich in ~/.bash_aliases diese Zeile eingefügt:

export PS1='\[\e[01;30m\]\t \[\e[00;37m\]\u@\h\[\e[01;37m\]:`[[ 
$(git status 2> /dev/null | tail -n1) != "nothing to commit (working 
directory clean)" ]] && echo "\[\e[31m\]" || echo "\[\e[32m\]"`
$(__git_ps1 "(%s) \[\e[00m\]")\[\e[01;34m\]\w\[\e[00m\]\$ '

Es ist eine Zeile, hier aber umgebrochen damit es "lesbar" bleibt.

Damit das klappt sollte das bash-completion Paket installiert sein. Sonst muss man /etc/bashcompletion.d/git gemäss der darin enthaltenen Instruktionen aus .bashrc sourcen und den Prompt setzen.

Python Datumshandhabung

2012-01-30 16:56 Programmieren, Python

Ich musste heute zufällige Datumswerte zwischen min_year und max_year erzeugen. Der Ansatz schien mir klar: umwandeln in ein int-basiertes Format, zufällige Auswahl eines integers im verfügbaren Bereich, zurückwandeln in ein Datum.

Tatsächlich schien mir die Lösung einfach zu sein:

import random
import time
min_year = 1950
max_year = 2020
a = time.mktime((min_year, 1, 1, 0, 0, 0, 0, 0, 0))
b = time.mktime((max_year, 1, 1, 0, 0, 0, 0, 0, 0))
value = time.localtime(random.randint(a, b))
chosen_year = value.tm_year

Nun, auf Linux lief das ganz gut, nicht aber auf Windows. In der Doku des time Moduls steht prominent geschrieben, dass time auf der C-Runtime basiert und somit so in etwa 1970-2038 abdeckt.

Zum Glück gibt es auch noch das datetime Modul. Damit kann man das einfach lösen mit einem Jahresbereich von 1-9999!

import random
from datetime import date
min_year = 1950
max_year = 2020
a = date(min_year, 1, 1).toordinal()
b = date(max_year, 12, 31).toordinal()
value = date.fromordinal(random.randint(a, b))
chosen_year = value.year

Und der Code ist erst noch einfacher und schöner!

Debian Netbook ohne X

2012-01-29 10:02 Linux

Manchmal möchte ich gerne im Zug ein bisschen arbeiten oder schreiben. Dazu habe ich einen Dell Notebook. Leider ist der relativ schwer. Seit längerem habe ich aber auch ein Acer Aspire One Netbook. Das würde sich ideal eignen von Grösse und Gewicht her. Bisher konnte ich es aber nicht nutzen, weil es leider den Intel GMA 500 Grafikchip hat und der ist im Linux Kernel nicht oder nicht gut unterstützt. Früher scheint ein guter Treiber existiert zu haben (poulsbo), der fiel weg (aber kommt scheinbar mit Linux 3.3 wieder verbessert rein).

Nun, dieser Zustand führte bei mir dazu, dass der Netbook herumlag und Staub ansammelte.

Jetzt habe ich einen neuen Anlauf genommen und mir gedacht, wieso ich überhaupt X benötige? Ich will ja nur ein bisschen in emacs schreiben und in Python programmieren. Das müsste doch mit reinem Textmodus möglich sein.

Gesagt getan. Ich nahm ein Debian 6 ISO image, schob es auf einen USB-Stick mit

dd if=debian6.iso of=/dev/sdd bs=4m; sync

steckte den Stick in den Netbook und startete diesen. Ich wählte die Basisinstallation ohne die "Desktop-Umgebung". Damit erhielt ich eine reine Textmodus-Installation.

Damit ich nicht auf 80x24 beschränkt bin, editierte ich noch /etc/default/grub und änderte

GRUB_CMDLINE_LINUX_DEFAULT="quiet"

in

GRUB_CMDLINE_LINUX_DEFAULT="quiet vga=0x318"

So habe ich eine angenehm kleine Schrift und entsprechend viel Text auf dem Bildschirm.

Nun habe ich eine schöne Arbeitsumgebung, die absolut auf die Basics beschränkt ist. Genau das gefällt mir. Nicht zuviel Schnickschnack. Konzentration auf das Wesentliche: git, emacs, python. Was braucht es mehr?

Ein bisschen muss ich schon noch warm werden mit dem neuen Setting. Zum Beispiel war ich anfangs unsicher, wie der Batteriestand ist. Bis ich herausfand dass es dafür das acpi Kommando gibt.

Zwei Sachen klappen noch nicht: Wlan und sleep/suspend/hibernate.

Das Wlan könnte ich, denke ich, noch hinkriegen, denn es ist ein Broadcom b43 chip drin. Der sollte eigentlich unterstützt sein. Oder man sollte ihn über ndiswrapper zum Laufen kriegen. Im Moment ist mir das nicht so wichtig, weil ich unterwegs kein Netz brauche und sowohl im Büro wie zuhause Zugriff aufs LAN habe.

Dass sleep/suspend/hibernate nicht richtig tut, ist ein bisschen blöder. Das Schlafen klappt noch, nicht aber das Aufwachen. Der Bildschirm wird nicht geweckt. Dafür gibt es einige Tricks, von denen ich ein paar schon ausprobiert habe, aber bisher ohne Erfolg. Nun, so fahre ich die Kiste halt jeweils runter. Booten und runterfahren ist sowieso blitzschnell, also ist es nicht tragisch. Aber es wäre schön wenn es klappen würde.

Python Fallstrick mit Default-Werten

2011-12-07 16:11 Programmieren, Python

Heute lief ich in eine Falle, die ich eigentlich schon kannte. Bei diesem Beispielcode:

>>> X = 12
>>> class Test(object):
...   def __init__(self, x=X):
...     self.x = x
... 
>>> X = 13
>>> X
13
>>> t = Test()
>>> t.x
12

dachte ich, dass die letzte Zeile 13 sein sollte. Schliesslich wird Test erst instanziiert, wenn X schon 13 ist. Das spielt aber keine Rolle, weil die Default-Werte zum Zeitpunkt der Klassendefinition evaluiert werden.

Wobei es nicht eine vollständige Evaluation ist, wohl eher das Speichern des (lexikalischen) Frames, sodass das Binding fixiert ist. Denn der folgende Code:

>>> X = [12]
>>> class Test(object):
...   def __init__(self, x=X[0]):
...     self.x = x
... 
>>> X[0] = 12
>>> X
[12]
>>> t = Test()
>>> t.x
12
>>> X = [11]
>>> X
[11]
>>> t = Test()
>>> t.x
12

zeigt, dass es funktioniert, solange man das Binding von X selber nicht ändert. X[0] wird aber durchaus zum Instanziierungszeitpunkt evaluiert.

Counter Strings in Python

2011-11-29 11:51 Programmieren, Python, Testen

James Bach hat in seinem Blog die Counter Strings vorgestellt. Eine geniale Idee. Er erzeugt sie mit einem Perl-Programm (PerlClip). Ich habe nun den Teil der Counter-String-Erzeugung nach Python übersetzt:

#!/usr/bin/env python3

# counterstring adapted from the code in "perlclip" package (see e.g. james bach)

# The idea is to start at the end of the string. The end must be a *
# character (or whatever the indicator character is). So the preceding
# number is obviously the target length. Preceding to this number is a
# * again, whose position can be calculated in the same manner.
#
# Since this builds the counter string in reverse, the position
# strings have to be added reversed and the final result string is
# reversed also.

def generate_counter_string(target_length, char="*"):
    result = ""
    pos = target_length
    while True:
        if len(result) + len(str(pos)) + 1 > target_length:
            result += char * (target_length - len(result))
            break
        result += char + str(pos)[::-1]
        pos -= len(str(pos)) + 1
    return result[::-1]

if __name__ == "__main__":
    print(generate_counter_string(int(sys.argv[1])))

Und hier die ersten paar Strings:

>>> from counterstring import *
>>> for length in range(20):
...   print(generate_counter_string(length))
... 

*
2*
*3*
2*4*
*3*5*
2*4*6*
*3*5*7*
2*4*6*8*
*3*5*7*9*
*3*5*7*10*
2*4*6*8*11*
*3*5*7*9*12*
*3*5*7*10*13*
2*4*6*8*11*14*
*3*5*7*9*12*15*
*3*5*7*10*13*16*
2*4*6*8*11*14*17*
*3*5*7*9*12*15*18*
*3*5*7*10*13*16*19*

Ältere Einträge