Statistiken via Subversionhistory

Nach einem erfolgreichen Projekt ist es interessant, was denn so alles gelaufen ist. Bei der Verwendung von Subversion (oder natürlich auch einem anderen Versionskontrollsystem) ist es „leicht“, die History einfach nach den Taten zu analysieren und daraus Berichte zu erstellen. Einfach deswegen in Anführungszeichen, weil dies natürlich händisch gesehen zuviel Zeit beanspruchen würde.

Für diesen Fall gibt es StatSVN, ein kleines in Java entwickeltes Tool, welches für eine Working Copy die komplette History in einem HTML-Report (wahlweise auch XML/XDOC) visualisiert. Dabei werden sowohl Tabellen als auch Diagramme erstellt – genial Sache! Da komplett über Kommandozeile lauffähig, ist eine Integration in Ant/Maven kein Problem; ebensowenig in andere Buildscripts.

Nachdem man eine neue Working Copy erstellt hat (bevorzuge ich mal an dieser Stelle), reichen 2 Befehle zum Generieren:

svn log -v --xml [ort] > svn.log

erstellt eine XML-Log der Commits, dabei ist „Ort“ natürlich optional und kann bspw. der Ort der Workingcopy sein (in Scripts)

java -jar statsvn.jar {working-copy-dir} {svn.log}

erstellt schließlich den Bericht. Wichtig sind dabei vor allem die Paratemer -output-dir, -threads. Die letzten beiden Parameter sind Pflicht.

Tatsächlich sollte man sich jedoch vorsehen, auf welchem Repository man es ausführt. Zwar lässt sich die Threadzahl (Standard 25) einstellen, aber es gibt auch Server, die damit absolut nicht klarkommen. Für diesen Fall empfehle ich das Spiegeln des kompletten Repositories auf die lokale Festplatte; dann muss ein neuer Checkout gemacht werden sowie zwischenzeitlich ein weiterer Sync der Repositories, aber das Generieren der Statistiken funktioniert wesentlich(!) schneller.

Mit dieser Anleitung ist ein Spiegel schnell eingerichtet, mittels dem letzten Befehl (svnsync sync…) wird das Repository auch später schnell gesynct, ähnlich einem svn update.

Sixt wirbt mit Ulla (Gang 2)

Super, dass man der Frau Ministerin den Dienstwagen in Alecante geklaut hat – das sollte mittlerweile jeder mitbekommen haben. Ist schließlich Sommerloch. Das der Wagen sogar mittlerweile wieder da, vielleicht der eine oder andere auch.

Aber Sixt, durchaus bekannt für manche kreativen Werbeideen, legte bereits am Montag mit einer Werbung vor. Super. Jetzt aber haben sie, meine ich, doch den Vogel abgeschossen. Genial 🙂

Aber seht selbst, via DerWesten!

Java-Anwendungen mittels Ant-Script in eine Drop deployen

Im Anschluss an meine vorangegangenen Artikel über das automatische Builden und Deployen einer Java-Anwendung (als Jar, als Mac-Applikation und als Windows-Exe) folgt nun ein Howto, wie man eine Drop von drop.io automatisch aktualisieren kann.

Leider gibt es derzeit weder eine Java-API-Implementierung der drop.io API noch einen Ant-Build-Task, letzteres ist dann natürlich keine Überraschung. Daher verwende ich iOrb, ein drop.io command line interface, entwickelt in Ruby. Daher ist auf dem System Ruby zwingend erforderlich — für Alternativen bin ich selbstverständlich offen.

Nach einer beispiellos simplen Installation ist iorb als Command verfügbar. In meinem Falle beginnen die Deploy-Apps mit „application-„, daher reicht ein Pattern, um alle zu löschen.

<target name="deployToDropio" depends="makeAll">
  <!-- Delete all application assets -->
  <exec executable="iorb">
    <arg line="destroy ${drop.drop_name}:/application-*/ --force" />
  </exec>
  <!-- Upload new versions -->
  <exec executable="iorb">
    <arg line="add deploy/Application.jar --drop-name ${drop.drop_name}" />
  </exec>
  <exec executable="iorb">
    <arg line="add deploy/Application.exe --drop-name ${drop.drop_name}" />
  </exec>
  <!-- zip mac app dir -->
  <zip destfile="deploy/Application.app.zip" basedir="deploy/Application.app" />
  <exec executable="iorb">
    <arg line="add deploy/Application.app.zip --drop-name ${drop.drop_name}" />
  </exec>
</target>

Vor dem ersten Starten muss/will iOrb eine Profildatei in ~/.iorbrc anlegen. Dafür ist ein API-Token von drop.io notwendig.

Dort werden auch im Yaml-Format die angelegten Drops gespeichert. Falls man bereits im Vorfeld eine Drop angelegt hat, so kann man diese Datei auch später im einen Texteditor entsprechend bearbeiten. Dort werden auch die Passwörter und Tokens abgelegt.

Java-Anwendungen mit Exe-Wrapper

Bereits vor einigen Wochen hatte ich hier und dort beschrieben, wie man mit Eclipse/Ant seine Anwendung per Knopfdruck automatisiert deployen kann. Da es unter manchen Windows-Systemen zu Schwierigkeiten kommt, eine Jar-Datei zu starten (bspw. nicht verknüpft mit dem Jar-Launcher) empfiehlt es sich natürlich, für jene einen kleinen Exe-Wrapper zur Verfügung zu stellen. Launch4j bietet neben dieser Funktionalität auch diverse andere Tweaks: Splashscreen, Java-Download-Hinweis, JVM-Arguments und vieles mehr. Dabei gibt es Launch4j in zwei Modi: Im Gui-Modus lassen sich alle Einstellungen konfigurieren (und testen) und anschließend speichern, im Befehls-Modus wird eben eine solche Konfigurationsdatei erwartet.

Launch4j arbeitet selber mit Ant, daher ist die Integration in bestehende Build-Tasks sehr einfach. Wahlweise konfiguriert man die Optionen direkt im Hauptbuildscript oder verwendet ein eigenes Script, welches man durch die Gui erhält.

In dem eigenen Buildscript definiert man den Task etwa mit:

<taskdef name="launch4j"
    classname="net.sf.launch4j.ant.Launch4jTask"
    classpath="${launch4j.dir}/launch4j.jar :${launch4j.dir}/lib/xstream.jar" />

wobei launch4j.dir auf das gesamte Verzeichnis zeigt (Hinweis.. es werden mindestens bin, lib und conf benötigt).

Anschließend kann mit einem beherzten <launch4j configFile=“build_data/launch4j.xml“ /> bereits der Prozess gestartet werden.

Beispielhafter Inhalt der build_data/launch4j.xml:

	<launch4jconfig>
		<dontwrapjar>false</dontwrapjar>
		<headertype>gui</headertype>
		<jar>../deploy/Application.jar</jar>
		<outfile>../deploy/Application.exe</outfile>
		<errtitle>Please download Java 6.</errtitle>
		<cmdline />
		<chdir />
		<priority>normal</priority>
		<downloadurl>http://java.com/download</downloadurl>
		<supporturl />
		<customprocname>false</customprocname>
		<stayalive>false</stayalive>
		<manifest />
		<icon>Application_32x32.ico</icon>
		<jre>
			<path />
			<minversion>1.6.0</minversion>
			<maxversion />
			<jdkpreference>preferJre</jdkpreference>
		</jre>
	</launch4jconfig>

Tab-Management in Java

Die im Rahmen unserer Diplomarbeit entstehende Anwendung verfügt unter anderem auch über ein TabbedPane, in welchem mehrere Panels mit Informationen angezeigt werden. TabbedPane, das ist in etwa die gleiche Art wie Tabs in einem Browser.

Erste Usability-Versuche zeigten, das gewisse Aktionen wie „Alle Tabs schließen“ aus Organisationsgründen fehlen, also flugs ran.. wären da nicht ein paar Probleme.

Einerseits verfügt leider das Standard-TabbedPane nicht über einen „Schließen“-Knopf, so das man entweder zu obskuren Hacks oder auf die TabbedComponent-Erweiterung aus dem JDK6 angewiesen ist. Kurze Erläuterung: Damit kann man quasi den Tab-Header komplett selber zeichnen, also auch inkl. eigener Panels, Buttons, usw.

Andererseits gibt es natürlich kein Tab-Management. Es gibt kein „Aktuellen Tab schließen“, kein „Alle Tabs schließen“ oder auch „Nächsten Tab wählen“. Weder in einer Menubar noch als Popupmenu via Kontextmenu auf den Tab-Header.

Also, selber bauen! Es gibt natürlich eine Reihe von Möglichkeiten, aber das beste Rezept erscheint mir eine Mischung aus:

  • Die TabbedPane-Komponente, die Änderungen mittels firePropertyChange weitergibt, vorgeschlagene Kandidaten sind: openTabItem(null, title), closeTabItem(title, null) und selectedTabItem(null, title). Damit lassen sich alle o.g. Aktionen auf das Menu spiegeln.
  • Die Menubar, welche die Liste der Einträge und die Aktionen bereitstellt. Die Aktionen werden durch eine externe Komponente (nennen wir sie mal Controller) ausgeführt.
  • Spezieller TabChangeListener, welcher die o.g. Aktionen abfängt und die Änderungen an die Menubar weitergibt.
  • Ein Popupmenu (für das Kontextmenu) schickt die Commands direkt an o.g. Controller.

tab-managament

Die Lösung ist derzeit in die Applikation eingefügt, aber ich plane, das ganze als autonomes Package demnächst zu extrahieren.