Java Getriebe

Java und NetBeans

Subversion Revision als Implementation Version verwenden

Das Modulsystem von NetBeans sieht für jedes Modul seiner RCP Anwendungen (also auch der IDE) eine Versionsnummer von. Anhand dieser Versionnummer erkennt der Plugin Manager ob sich ein Modul z.B. in einem Update Center erneuert hat oder nicht.

Diese Versionsnummer wird in den Eigenschaften eines Modulprojekts unter „API Versioning“ eingetragen. Mindestens die „Specification Version„, also die Version der API mit der auf dieses Modul zugegriffen wird und wahlweise einer „Implementation Version„, die (wie ich sie nenne) „Bugfix Nummer„.

Aber genau diese „Bugfix Nummer“ wird oft nicht inkrementiert, wenn man einen Fehler behoben hat. Die API des Moduls hat sich meistens nicht verändert, darum wäre ein Ändern der „Specification Version“ falsch. Um dem Modul aber trotzdem automatisch eine neue Version verpassen zu können, habe ich das Buildskript etwas erweitert und verwende jetzt die Subversion Revisionsnummer des letzten Commits als „Implementation Version“.

Am Besten funktioniert diese Lösung in Suiteprojekten und seinen Modulen. Dabei ist es auch egal, ob jetzt es eine RCP Anwendung oder eine Modulsammlung ist. Ziel war es für mich ein einfaches und trotzdem universelles Vorgehen beim Erstellen neuer Module zu erreichen.

Für diese Lösung ist es Voraussetzung, dass sich ein Subversion Kommandozeilen Client im Standardsuchpfad des Systems (%PATH% unter Windows) befindet.

Zunächst muss dieses ANT Skript ohne weitere Anpassung in das nbproject Verzeichnis des Suiteprojekts kopiert werden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?xml version="1.0" encoding="UTF-8"?>
<project name="svnversion" default="svnversion" basedir="..">
  <!--
   copy this file to your nbproject folder of your suite project
   (or to modules' nbproject for stand-alone modules)

   add these lines to your modules build.xml:
   ~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~
   <import file="${suite.dir}/nbproject/svnversion.xml"/>
   <target name="build-init" depends="svnversion.build-init,harness.build-init"/>
   ~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~~~~ 8< ~~~~~~~
   (remove "${suite.dir}/" for stand-alone modules)

   set "Append Implementation Versions Automatically" in module settings.

   See current version of this file at
   http://blog.nigjo.de/netbeans/2010/09/subversion-revision-als-implementation-version-verwenden/
   -->
  <target name="-svnversion-init">
    <!-- get svn binary file name -->
    <condition property="svn.binary" value="svn.exe">
      <os family="windows"/>
    </condition>
    <!--TODO: Please test this in a non windows environment -->
    <property name="svn.binary" value="svn"/>

    <!-- check for existance of binary -->
    <condition property="svn.exist">
      <and>
        <!-- only if svn.binary is found in system search path -->
        <or>
          <available file="${svn.binary}" filepath="${java.library.path}"/>
          <available file="${svn.binary}"/>
        </or>
        <!-- only if module is already under svn control -->
        <available file="${basedir}/.svn"/>
        <!-- replacement can be disabled in modules project.properties -->
        <not><istrue value="${svnversion.disable}"/></not>
      </and>
    </condition>
  </target>

  <target name="build-init" depends="-svnversion-init" if="svn.exist">
    <!-- define svn macro -->
    <macrodef name="svn">
      <attribute name="command"/>
      <attribute name="options" default=""/>
      <attribute name="dir" default="${basedir}"/>
      <attribute name="output" default=""/>
      <sequential>
        <exec executable="${svn.binary}" dir="@{dir}" output="@{output}">
          <arg value="@{command}"/>
          <arg line="@{options}"/>
        </exec>
      </sequential>
    </macrodef>

    <!-- redirect manifest file -->
    <property name="manifest.mf" value="build/manifest-svn.mf"/>
    <property name="manifest.source.mf" value="manifest.mf"/>

    <!-- check module project settings -->
    <property file="${manifest.source.mf}" prefix="svnmf"/>
    <fail if="svnmf.OpenIDE-Module-Specification-Version"
     message="Please enable 'Append Implementation Versions automaticaly'"/>

    <!-- query svn info -->
    <mkdir dir="build"/>
    <svn command="info" options=". --xml" output="build/svninfo.xml"/>
    <xmlproperty file="build/svninfo.xml" prefix="svninfo"
     collapseattributes="true"/>

    <!-- set "real" implementation version -->
    <copy file="${manifest.source.mf}" tofile="${manifest.mf}"/>
    <manifest file="${manifest.mf}" mode="update" >
      <attribute name="OpenIDE-Module-Implementation-Version"
       value="${svninfo.info.entry.commit.revision}"/>
    </manifest>
  </target>

</project>

Jedes Modul muss einzeln angepasst werden, aber dafür ist das Vorgehen immer das gleiche:

  1. Das Modul selber sollte unter Versionskontrolle von Subversion stehen. Das Skript erzeugt zwar keinen Fehler, aber die Versionsnummer wird nicht automatisch angepasst.
  2. In der build.xml des Moduls muss hinter dem ersten import die folgenden beiden Zeilen ohne Änderung eingefügt werden
    1
    2
    <import file="${suite.dir}/nbproject/svnversion.xml"/>
    <target name="build-init" depends="svnversion.build-init,harness.build-init"/>
  3. In den Eigenschaften des Modulprojekts sollte die „Specification Version“ „dreistellig“, also „1.0.0“ lauten. Dies ermöglicht es später auch kleinere Änderungen an der API mit „kleineren“ Versionssprüngen zu dokumentieren. Für das Skript selbst hat dies keine Auswirkungen.
  4. Unter „Implementation Version“ muss ein beliebiger Wert (z.B. „0“) eingetragen werden. Dieser Wert wird auch verwendet, wenn kein SVN Client im System vorhanden ist.
  5. Danach kann die Option „Append Implementation Versions Automatically“ ausgewählt werden.

Und das war es auch schon. Ab sofort sollte sich die „Bugfix Nummer“ automatisch bei jedem Commit aktualisieren. Der Plugin Manager erkennt somit jede Änderung und trotzdem ist kein manueller Eingriff notwendig.

3 Responses to Subversion Revision als Implementation Version verwenden

  1. Moin!

    Es gibt da eine Alternative, um die letzte Revision zu ermitteln. Ist mit den aktuellen lokalen svn-Repositories kompatibel:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <target name="-pre-jar">
      <!-- Die aktuelle Revisionsnummer aus der entries Datei lesen-->
      <loadfile property="dist.revision" srcFile="./.svn/entries">
        <filterchain>
          <headfilter lines="1" skip="3"/>
          <deletecharacters chars="\n"/>
        </filterchain>
      </loadfile>
    </target>

    Ich nutze das vornehmlich für meine Java SE Projekte (wie man an dem Target sehen kann). Aber der Einsatz in der Implementation Version von Modulen ist auch recht nett 🙂

    Beste Grüße,
    Josch.

  2. Kleiner Nachtrag, mit dem es auch möglich ist einen svn client zu benutzen, der nicht zwingend im Suchpfad des System liegt:

    Im Target -svnversion-init muss die Zeile

    1
    2
    <!-- only if svn.binary is found in system search path -->
    <available file="${svn.binary}" filepath="${java.library.path}"/>

    durch die Zeilen

    1
    2
    3
    4
    5
    <!-- only if svn.binary is found in system search path -->
    <or>
      <available file="${svn.binary}" filepath="${java.library.path}"/>
      <available file="${svn.binary}"/>
    </or>

    ersetzt werden. Dann kann man in der platform-private.properties des Suiteprojekts die Variable svn.binary auf den gewünschte CLI-Client verweisen lassen und schon wird die Implementation Version wieder korrekt gesetzt.

    Jens
    ps: Dieses Vorgehen bietet keinen Schutz vor Fehlbedienung. Man sollte schon einen korrekten SVN Client angeben, wenn man das Skript nutzen möchte 😉
    pps: Ich habe das Beispiel im Artikel angepasst.

  3. Pingback: Automatische “Implementation Version” für Module |