Mercurial, hooki i python

Data publikacji: 2013-04-19 | Tagi:

Jesteśmy tylko ludźmi, a mylić się i błądzić jest rzeczą jak najbardziej ludzką. Cały trik polega na tym, żeby z błądzeń i pomyłek wyciągać wnioski na przyszłość. O ile jestem w stanie być wierny tej zasadzie w około 80%, to pozostałe 20% stanowią błędy, które popełniam zawsze i wszędzie, choćbym nie wiem jak bardzo się starał :).

Jednym z tych błędów jest wprowadzenie tzw. tymczasowych zmian w kodzie i zapomnienie o nich przed wrzuceniem serwisu na produkcję. W efekcie strona radośnie pobłyskuje wyrazem DUPA!!! w najbardziej czytelnym miejscu, albo świeci pustymi fragmentami, bo tymczasowo i w celach testowych wyciąłem spory fragment template_tagów.

Powodów takich działań może być wiele i nie będę się tutaj zagłębiał w usuwanie przyczyn, natomiast mam pomysł jak zapobiec skutkom. Potrzebny będzie nam mercurial, python oraz trochę oleju w głowie.

1. Zaczynamy od rzeczy najprostszych

W pliku ~/.hgrc dodajemy następujące linie:

[hooks]
pretxncommit.blocked = test `hg export tip | grep "XXX" | wc -l` -eq 0

Teraz za każdym razem gdy hg napotka w commitowanym kodzie ciąg XXX nie dopuści do commitu i będziemy zmuszeni zerknąć do kodu i poprawić fragment, gdzie ów ciąg występuje.

Wystarczy przyjąć dodatkową zasadę, że przy tych nieszczęsnych zmianach do testów będziemy również dodawać XXX.

Przy okazji wyjaśniam - nie musi być to dokładnie taki sam ciąg - można wybrać dowolny - ja wybrałem sobie właśnie taki.

A co tak naprawdę dzieje się w pliku ~/.hgrc?

Pod zdarzenie pretxncommit (przed wysłaniem nowego commita do repozytorium) podpinamy ciąg poleceń shella, który zwraca nam ilość wystąpień zadanego ciągu. Jeśli ilość jest większa niż 0, mercurial nie pozwala wykonać commitu.

Niestety te rozwiązanie nie pokazuje nam, w którym pliku występuje feralny ciąg i używanie go ma sens tylko wtedy, gdy za jednym zamachem edytujemy niewielką ilość plików.

2. Kończymy na trochę trudniejszych

W katalogu domowym tworzymy plik keyword_block_hook.py i wklejamy do niego następującą treść:

#!/usr/bin/env python
import re


def keyword_block(difflines, keyword):
    linenum, header = 0, False

    for line in difflines:
        if header:
            # remember the name of the file that this diff affects
            m = re.match(r'(?:---|\+\+\+) ([^\t]+)', line)
            if m and m.group(1) != '/dev/null':
                filename = m.group(1).split('/', 1)[-1]
            if line.startswith('+++ '):
                header = False
            continue
        if line.startswith('diff '):
            header = True
            continue
        # hunk header - save the line number
        m = re.match(r'@@ -\d+,\d+ \+(\d+),', line)
        if m:
            linenum = int(m.group(1))
            continue
        # hunk body - check for an added line with trailing whitespace
        if line[0] not in "-" and keyword in line:
            yield filename, linenum
        if line and line[0] in ' +':
            linenum += 1
            

if __name__ == '__main__':
    import os, sys
    keyword = "XXX" 

    found = 0
    for filename, linenum in keyword_block(os.popen('hg export tip'), keyword):
        print >> sys.stderr, ('%s, line %d: blocking keyword found' %
                              (filename, linenum))
        found += 1

    if found > 0:
        sys.exit(1)

Nadajemy mu prawa do wykonywania:

chmod a+x keyword_block_hook.py

I dodajemy nowy wpis w ~/.hgrc w miejsce poprzedniego:

[hooks]
pretxncommit.keyword_blocked = ~/keyword_block_hook.py

Całość działa w sposób zbliżony do pierwszego rozwiązania, z tym że całe "mięcho" przerzucamy w chwili obecnej na pythona, a nie na polecenia powłoki. Dodajemy również kilka usprawnień, a szczególnie wyświetlanie informacji o nazwie pliku i numerze linii, w której występuje poszukiwany ciąg znaków.

Dzięki temu rozwiązaniu ustrzegłem się kilkukrotnie przed wysłaniem na produkcję kodu nie do końca przeznaczonego do publicznej prezentacji :).

3. Na zakończenie

Warto zapoznać się z książką (dostępną za darmo, online) hgbook.red-bean.com, albo chociaż z jej fragmentami. Na podstawie informacji zawartych w rozdziale o hookach stworzyłem powyższy kod.


Oceń ten post:
Podziel się:

comments powered by Disqus

IT w obrazkach: