15. elokuu 2011, 17:09

Git-repon aktiivisuus graafiksi

Tässä erilaisten projektien loukussa löysin itselleni pienen hengähdystauon kirjoittaessani bash-gnuplot -kaksikon, missä tutkin git-repojen aktiivisuutta graafin muodossa. Varmaan git gui tai tig hoitaa saman asian, mitä tämä, mutta otin tämän ihan mielenkiinnolla vastaan.

Pitäisiköhän koodia vähän tutkiskella? Keskeinen ongelma oli saada gnuplot tekemään oikeannäköistä graafia. Sitä pohdin jo kuukausi sitten kysymyksessäni StackOverflow’ssa. Kuten näette, gnuplot ei siihen taivu. En myöskään silloin jaksanut uhrata aikaani awkin kanssa säätämiseen.

Nyt kuitenkin jaksoin, ja sain jotain aikaiseksi. Parin päivän mittaan screenin ja vimin upean ScreenSend -skriptin avulla oli mukava työstää. Koodi on sievästi etenevää sorttia, joten sen voi esitellä sellaisenaan paloissa:

#!/bin/bash
# nice graph out of git repo commits

tempfile=`mktemp`

# obtain the first and last date:
read -a dates <<< "`git log --format="%ci"|awk '{printf "%s ", $1}'`"
startdate=${dates[ ((${#dates[@]} - 1)) ]}
enddate=${dates[0]}

Ensimmäinen vaihe on luoda temppitiedosto ja ottaa repon ensimmäinen ja viimeinen aktiivinen päivä ylös. Tämän saan bash-taulukkoon, josta kryptisellä haulla haetaan taulukon viimeinen arvo aloituspäiväksi. Lopetuspäiväkin valitaan sieltä.

Nyt ideana on generoida päivämääriä aloitus- ja lopetusajan peittämiseksi, koska gnuplot ei itse osaa:

# generate day entries of zero
for d in $(seq $(date +%s -d $startdate) 86400 $(date +%s -d $enddate)) ; do
    date "+%F%t0%t0" -d @$d
done > $tempfile

Unix-timestamppien kanssa päivämäärälaskenta on onneksi suoraviivaista. Tuloste on muotoa

pvm         lisäykset  deletiot
2010-01-01  0          0

Ja nämä ovat aina nollia näissä bogussyötteissä: myöhemmin nimittäin kasaamme kaikki saman päivän sisällä tehdyt kommitit yhteen siisteyssyistä. Nyt haetaan varsinaiset tulosteet, jotka muotoillaan ylläolevaan muotoon awkin avulla näppärästi:

# append the actual git commits, do some parsing
git log --date=short --shortstat|awk '
/^Date:/ {
    printf "%s", $2
}
/^.+ files changed/ {
    print "\t" $4 "\t" $6
}' >> $tempfile

Git log ottaa vastaan myös kustomoituja syötemuotoja, mutta niissä muodoissa ei ole mahdollista saada lisäyksiä ja poistoja (--shortstat) mukaan. Siispä käytämme tätä ratkaisua. Nyt tiedostossa $tempfile on paljon päivämääriä tyhjin tilastoin, sekä oikeita tilastoja. Karsimme näistä nyt summariikin, kunhan muistamme lajitella tiedoston ensin…

# gotta create a new tempfile
finaldata=`mktemp`

# now let awk combine entries 
sort $tempfile | awk '
{
    if($1 != olddate) {
        print olddate "\t" ins "\t" dels
        olddate = $1
        ins = 0
        dels = 0
    }
    ins += $2
    dels += $3
}
END{
    print olddate "\t" ins "\t" dels
}' > $finaldata

Uusi temppitiedosto tuntui olevan ainut järkevä vaihtoehto tähän. Lisäksi piti kirjoittaa epäelegantti END-lauseke loppuun, kun muuten olisi pitänyt vähän miettiäkin. Nyt meillä on tiedostossa $finaldata lajiteltu katsaus kutakin päivää. Arpomisen ja tarkastelujen perästä se näyttää toimivan: summat täsmäävät ja kaikkia päiviä löytyy, vaikka sitten nollatilastoin.

Gnuplot on viimeinen etappi matkallamme:

# finally, the graph

gnuplot -persist <<EOF
set xdata time
set timefmt "%Y-%m-%d"
set xtics rotate format "%Y-%m"
set style data boxes
set style fill solid
set object rectangle from screen 0,0 to screen 1,1 behind fc rgb "gray"
set grid
plot '$finaldata' using 1:2 t "ins"  lt rgb "green", \
     '$finaldata' using 1:3 t 'dels' lt rgb "red"
EOF

rm "$tempfile"
rm "$finaldata"

Tyypillistä gnuplot-magiaa, ei sen kummempaa. Tuloksissa pylväät jotenkin oudosti hyppivät, mutta voi johtua paljosta muustakin. Tämä kokonaisuus ei välttämättä anna hyvää kuvaa koko reposta, koska eri branchit jäävät käsittääkseni logien varassa piiloon. Omiin projekteihini ehkä kannustimeksi kuitenkin ihan kiva.

Tageja: , , ,

---
---

---

Aiheen vierestä