Versioning and signing jar files in Netbeans

Oktober 1st, 2010 by Gerrit Diesen Artikel diskutieren »

Hi again,

these days i’ve got the problem that i need to add a version number to the SteelSeries java component library and to be honest i had no idea how to realize it.

So after a short internet research i figured out that there is the ability to add version information to the manifest file that’s included in a jar file.

If you do not know what a manifest is or how it is embedded in the jar file you will find a detailled description here.

Now that i knew where to put the version information the question was how to get Netbeans adding this information automaticaly to the manifest file during the build process. Well Netbeans is using Ant under the hood to build your projects and because i knew ant build scripts from using the Hudson Continues Integration server it was easy to achieve this.

First of all you have to locate the build.xml file in your Netbeans projects folder. Simply open it in Netbeans itself and you will see something like this…

<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="SteelTest" default="default" basedir=".">
    <description>Builds, tests, and runs the project SteelTest.</description>
    <import file="nbproject/build-impl.xml"/>
    <!--
    There exist several targets which are by default empty and which can be 
    used for execution of your tasks. These targets are usually executed 
    before and after some main targets. They are: 
      -pre-init:                 called before initialization of project properties
      -post-init:                called after initialization of project properties
      -pre-compile:              called before javac compilation
      -post-compile:             called after javac compilation
      -pre-compile-single:       called before javac compilation of single file
      -post-compile-single:      called after javac compilation of single file
      -pre-compile-test:         called before javac compilation of JUnit tests
      -post-compile-test:        called after javac compilation of JUnit tests
      -pre-compile-test-single:  called before javac compilation of single JUnit test
      -post-compile-test-single: called after javac compilation of single JUunit test
      -pre-jar:                  called before JAR building
      -post-jar:                 called after JAR building
      -post-clean:               called after cleaning build products
    (Targets beginning with '-' are not intended to be called on their own.)
    Example of inserting an obfuscator after compilation could look like this:
        <target name="-post-compile">
            <obfuscate>
                <fileset dir="${build.classes.dir}"/>
            </obfuscate>
        </target>
    For list of available properties check the imported 
    nbproject/build-impl.xml file. 
    Another way to customize the build is by overriding existing main targets.
    The targets of interest are: 
      -init-macrodef-javac:     defines macro for javac compilation
      -init-macrodef-junit:     defines macro for junit execution
      -init-macrodef-debug:     defines macro for class debugging
      -init-macrodef-java:      defines macro for class execution
      -do-jar-with-manifest:    JAR building (if you are using a manifest)
      -do-jar-without-manifest: JAR building (if you are not using a manifest)
      run:                      execution of project 
      -javadoc-build:           Javadoc generation
      test-report:              JUnit report generation
    An example of overriding the target for project execution could look like this:
        <target name="run" depends="SteelTest-impl.jar">
            <exec dir="bin" executable="launcher.exe">
                <arg file="${dist.jar}"/>
            </exec>
        </target>
    Notice that the overridden target depends on the jar target and not only on 
    the compile target as the regular run target does. Again, for a list of available 
    properties which you can use, check the target you are overriding in the
    nbproject/build-impl.xml file. 
    -->

P L A C E   T H E   F O L L O W I N G   T A R G E T S   H E R E   !   !   !

</project>

Like it’s described in the text above there are different hooks where you could add your own stuff into the ant build script. Thinking about what kind of information to add to the manifest file i decided to not only add a version number but also a build number and in addition to this the subversion revision. This could be useful if someone would like to check out the sources for a specific version of the jar.

Means i need three things:

  • version number
  • build number
  • subversion revision

To achieve this information i will use two hooks in the build script

  • -post init
  • -post jar

Getting the subversion revision is easy and i found a ant target for this that looks like this…


   <!-- Extract the svn revision from subversion -->

   <target name="-post-init" description="Get the svn revision of the current build">
       <exec outputproperty="svna.version" executable="svnversion">
           <arg value="-c" />
           <redirector>
               <outputfilterchain>
                   <tokenfilter>
                       <replaceregex pattern="^[0-9]*:?" replace="" flags="g"/>
                       <replaceregex pattern="M" replace="" flags="g"/>
                   </tokenfilter>
               </outputfilterchain>
           </redirector>
       </exec>
   </target>

Next thing we need is the version and the build number. Ant is able to create a automatic increasing buildnumber everytime you run the build script so this is also no big deal. The version number could either be read from a text file or hardcoded in the build script.

In this example i hardcoded the version number directly into the build file because this number won’t change very often.

In addition to the version and build numbering you might also want to sign your jar automaticaly after it’s creation, well that’s again easy to achieve in ant but lets have a look at the ant target…

<!-- Add the version information to the jar, sign the jar and create
     create a copy of the jar containing the version number in the filename -->
<target name="-post-jar">
    <property name="version.num" value="1.0" />
    <buildnumber file="build.num" />
    <tstamp>
        <format property="NOW" pattern="yyyy-MM-dd HH:mm:ss z" />
    </tstamp>
    
    <!-- Add the version information to the manifest file -->
    <jar>
        <manifest>
           <attribute name="PROJECT_NAME-Version" value="${version.num}.${build.number}" />
           <attribute name="PROJECT_NAME-SVN-Revision" value="${svna.version}" />
           <attribute name="PROJECT_NAME-BuildStamp" value="${NOW}" />
       </manifest>

</jar>


    <!--Sign the jar file with you credentials -->
    <!--<signjar jar="${dist.jar}" alias="..." keystore="..." storepass="..." />-->
    
    <!-- Make a copy of the jar file and add the version number to the filename -->
    <copy file="${dist.jar}" tofile="${dist.dir}/PROJECT_NAME-${version.num}.jar" />
</target>

So as you can see in the file above the buildnumber will be generated by the tag <buildnumber> and will be stored in a file called „build.num“. If this file isn’t present it will be created automaticaly (might make sense to delete it for every new major version).

If you copy and paste this targets in the build.xml file of your project you only have to replace the PROJECT_NAME in the above examples with your project name and modify the version number and you are ready to go.

These modifications to the build.xml file will give you the following result in the manifest file of your jar.

Manifest-Version: 1.0

Ant-Version: Apache Ant 1.8.1

Created-By: 1.6.0_20-b02-279-10M3065 (Apple Inc.)

PROJECT_NAME-Version: 1.0.1

PROJECT_NAME-SVN-Revision: 1

PROJECT_NAME-BuildStamp: 2010-09-30 09:58:38 MESZ

For me this was the solution i was looking for but if someone has a trick how to improve it…PLEASE LET ME KNOW !!!

Follow me on twitter if you like…

 

Antwort verfassen