Use maven's "version" property in java and nsis code - java

we require the software version number of a maven project both in the java code and in the NSIS installer script. Following the DRY principle, the version number should be stored in the maven pom only. What is the best way to get this version number in the Java code as well as in the NSIS script? Updates on the version number should of course be distributed without the developer having to care about it.
The current approach: Wherever the version number is needed, ${"versionNr"} is inserted as a substitute. Then, during the maven build phase, all java and NSIS source files are filtered and the key is replaced by the version number. To avoid changes in the checked in source code, the filtered files are actually copied to a different location not within the scm. Having the original source and the source filtered by maven causes a lot of confusion, which I would like to avoid.
Any hints?

I typically put the version parameter (like ${project.version}) in a properties-file and only apply filtering on that one file in the maven build. Like
app.version=${project.version}
Then I use this properties file in the code to get the version.

pom.properties gets built into JAR file (to META-INF/maven/<groupId>/<artifactId>/pom.properties) when the project is packaged up. It looks something like:
#Generated by Maven
#Mon Sep 26 09:03:19 EST 2011
version=1.0-SNAPSHOT
groupId=my.project.group.id
artifactId=my-artifactid
You could read this as a resource in your Java code, and use Property API to read the version out.
Not sure whether NSIS scripts can read property files, but according to the source code of the NSIS plugin it creates a few !defines, including PROJECT_VERSION which gets the project version straight from the POM. Maybe you can use this.

Related

IntelliJ IDEA 2016 JAR run config: use variable version number

I have a jar built with maven, such that the version number included in the name, for example thing-1.0.0.jar.
In IntelliJ 2016, I'm then using a JAR run configuration to run the jar. My run configuration is set up like this:
The problem is that the Path to JAR config points to the exact filename, so every time I bump the version number, and the built jar filename changes, say thing-1.0.0.jar > thing-1.0.1.jar, I have to manually update the run configuration too, to run the newer version.
What I'd like to do instead:
ideally
Put the current version number in using some kind of variable, where the value would be retrieved from the project's pom. This would obviously be a specialised IntelliJ feature, and I'm not sure this exists.
or, good enough
Just match any version number with a regex, since just running whatever the latest built version happens to be solves my problem in practice. I've played around trying to do this in the Path to JAR field, but it just reads my regex as a literal value - if this is indeed a feature, I can't find the right syntax for using it.
So, are either of these solutions possible? Or is there another, better way to achieve this goal with IntelliJ 2016 run configurations? I've googled this in every phrasing I can think of and and have looked at the docs and can't find anything.
Note: I know I could use a maven plugin to handle the running, but I'd prefer to avoid an extra dependency. I want to do this with the integrated IntelliJ tooling, if possible.

Converting Ant project to Gradle with dated build

Currently, every time the source in my ant project is built a java file with a static final variable with the version number is generated. The version number is formatted as yyyyMMdd so that it is always increasing. My problem is that I'm currently checking in the resulting build jar into source control (which I view as a failure, since I don't believe that I should be checking in binaries that are created from the build process).
I was wondering if there was an easy way to generate and write a date based version number to a java file in gradle before compilation, and also if there was a way to somehow only regenerate this version number when I'm building in development and not when someone else is going to rebuild the same version from source. It's a difficult separation of tasks, but I'm hoping someone has had some experience with it before.
You are correct when it comes to not include binaries into source control - of course some type of binaries - I mean, the output of compilation.
Basically modifying sources by build tools is not a good practice, it may cause many problems. Instead, I suggest to add a plain old properties file that will be filtered during build and an entry within it will be substituted with the current date. This file will be included into the binary output of compilation (namely jar file) but can be ignored in source control since it's irrelevant.
What are you asking about can be done in gradle, however it's not a good idea (as I mentioned).

Rebuilding QuickFIX/J with Ant

The User FAQ of QuickFIX/J describes the opportunity to rebuild the data dictionary of QuickFIX/J to customize the application.
It is described in the FAQs tis way:
You'll need ant installed.
QF/J generates the source from the DDs in core/src/main/resources. Make a back up of the one you're going to alter, and then alter it however you need to.
Then rebuild as follows:
ant jar
You will be prompted for a release number; this just determines the suffix given to the jar names. Enter whatever you want.
Wait for build to finish
Find your brand-new QF/J jars in core/target/
Unfortunately I could not find the build.xml that I have to invoke with ant.
Maybe you have experience with this issue and can help me.
Thanks for your help!
Edit:
I've found a further guide to rebuild QuickFIX/J from the official QuickFIX page:
Building QuickFIX/J
These instructions are for developers who don't want to use the prebuilt binaries or are intending to modify and rebuild the QuickFIX/J code. If you are building the code from the command line you'll need to download and install Ant (version 1.6.3 or newer). If you are building from Eclipse, Ant is included. Building from source requires Java 5+. There are no Java 1.4 sources.
Check out the code from Subversion. See the Subversion guide at Source Forge for more details on access. You will usually want to checkout the trunk directory from the Subversion repository.
Change directory to the top-level directory of the checked out code. You should see a build.xml file.
Run ant jar to build the QuickFIX/J and examples jar files. This will also generate all the FIX message-related code for the various FIX versions.
There is an option for the code generator to use BigDecimal instead of double for fields like price and quantity. To enable this feature pass a -Dgenerator.decimal option on the command line when running the generate.code Ant target.
I've downloaded the zip from sourceforge, but the whole diretory (and its subdirectories) doesn't contain a build.xml?!?!
Thanks for help!!

How can I tell NetBeans to use the latest available version of a JAR for a library?

I have a Netbeans project with a library defined which includes several JARs. These JARs are versioned like lib\blah\com.blah.wibble.jar_0.6.1.201004161543 . These are nightly builds from another project so that version changes often.
I know I can point NetBeans at the specific JARs with the version name, but this means that every time I get a new version I have to update the NetBeans library.
I can also strip the version name from the JARs, but this makes it hard to track down bugs. "What version of the blah JARs?" is usually the second thing we ask when we find a bug.
Is it possible to tell Netbeans to use included com.blah.wibble.jar_[??????] where ???? is some sort of automatic pointer to use the latest available version?
Consider converting into a maven project and publish new builds into the repository.
Recently logback and other logging frameworks have had added code that adds jar versions to stacktraces based on information in MANIFEST.MF, which is very helpful in reproducing bugs.
For your situation a continous build server might be extremely useful, then you can reproduce exactly those builds reported by users as all information is present in the build server, just by having the build ID from the user.

Alternative to binaries in Subversion

Some of my colleagues are convinced that committing build artefacts to the subversion repository is a good idea. The argument is that this way, installation and update on the test machines is easy - just "svn up"!
I'm sure there are weighty arguments against this bad practice, but all I can think of are lame ones like "it takes up more room". What are the best, killer reasons to not do this? And what other approaches should we do instead?
This is for Java code if that makes a difference. Everything is compiled from Eclipse (with no automated PDE builds).
When I say add the build artifacts, I mean a commit would look like this:
"Added the new Whizbang feature"
M src/foo/bar/Foo.java
M bin/Foo.jar
Each code change has the corresponding generated jar file.
In my opinion the code repository should only contain source code as well as third party libraries required to compile this source code (also the third party libraries might be retrieved with some dependency management tool during the build process). The resulting binaries should not get checked in along with the source code.
I think the problem in your case is that you don't have proper build scripts in place. That's why building a binary from the sources involves some work like starting up eclipse, importing the project, adjusting classpathes, etc...
If there are build scripts in place, getting the binaries can be done with a command like:
svn update; ant dist
I think the most important reason not to checkin the binaries along with the source is the resulting size of your repository. This will cause:
Larger repository and maybe too few space on versioning system server
Lots of traffic between versioning system server and the clients
Longer update times (imagine you do an SVN update from the internet...)
Another reason might be:
Source code is easily comparable, so lots of the features of a versioning system do make sense. But you can't easily compare binaries...
Also your approach as described above introduces a lot of overhead in my opinion. What if a developer forgets to update a corresponding jar file?
Firstly, Subversion (and all others nowadays) are not source code control managers (I always thought SCM means Software Configuration Management), but version control systems.
That means they store changes to the stuff you store in them, it doesn't have to be source code, it could be image files, bitmap resources, configuration files (text or xml), all kinds of stuff. There's only 1 reason why built binaries shouldn't be considered as part of this list, and that's because you can rebuild them.
However, think why you would want to store the released binaries in there as well.
Firstly, its a system to assist you, not to tell you how you should build your applications. Make the computer work for you, instead of against you. So what if storing binaries takes up space - you have hundreds of gigabytes of disk space and super fast networks. Its not a big deal to store binary objects in there anymore (whereas ten years ago it might have been a problem - this is perhaps why people think of binaries in SCM as a bad practice).
Secondly, as a developer, you might be comfortable with using the system to rebuild any version of an application, but the others who might use it (eg qa, test, support) might not. This means you'd need an alternative system to store the binaries, and really, you already have such a system, its your SCM! Make use of it.
Thirdly, you assume that you can rebuild from source. Obviously you store all the source code in there, but you don't store the compiler, the libraries, the sdks, and all the other dependant bits that are required. What happens when someone comes along and asks "can you build me the version we shipped 2 years ago, a customer has a problem with that version". 2 years is an eternity nowadays, do you even have the same compiler you used back then? What happens when you check all the source out only to find that the newly updated sdk is incompatible with your source and fails with errors? Do you wipe your development box and reinstall all the dependencies just to build this app? Can you even remember what all the dependencies were?!
The last point is the big one, to save a few k of disk space, you might cost yourself days if not weeks of pain. (And Sod's law also says that whichever app you need to rebuild will be the one that required the most obscure, difficult to set up dependency you were ever glad to get rid of)
So store the binaries in your SCM, don't worry over trivialities.
PS. we stick all binaries in their own 'release' directory per project, then when we want to update a machine, we use a special 'setup' project that consists of nothing but svn:externals. You export the setup project and you're done as it fetches the right things and puts them into the right directory structure.
A continuous integration server like Hudson would have the ability to archive build artifacts. It doesn't help your argument with "why not" but at least it is an alternative.
I'm sure there are weighty arguments
against this bad practice
You have the wrong presumption that committing "build artifacts" to the version control is a bad idea (unless you wrongly phrased your question). It is not.
It is ok, and very important indeed, to keep what you call "build artifacts" in version control. More than that, you should also keep compilers and anything else used to transform the set of source files to a finished product.
In five years from now, you'll certainly be using different compilers and different build environments, that may happen to not be able to compile today's version of your project, for whatever reason. What could be a simple small change to fix a bug in a legacy version, will transform into a nightmare of porting that old software to current compilers and build tools, just to recompile a source file that had a one-line change.
So, there is no reason you should be so afraid of storing "build artifacts" in version control. What you may want to do is to keep them in separate places.
I suggest separating them like:
ProjectName
|--- /trunk
| |--- /build
| | |--- /bin <-- compilers go here
| | |--- /lib <-- libraries (*.dll, *.jar) go here
| | '--- /object <-- object files (*.class, *.jar) go here
| '--- /source <-- sources (*.java) go here
| |--- package1 <-- sources (*.java) go here
| |--- package2 <-- sources (*.java) go here
You have to configure your IDE or your build scripts to place object files in /ProjectName/trunk/build/object (perhaps even recreating the directory structure under .../source).
This way, you give your users the option to checkout either /ProjectName/trunk to get the full building environment, or /ProjectName/trunk/source to get the source of the application.
In ../build/bin and ../build/lib you must place the compilers and libraries that were used to compile the final product, the ones used to ship the software to the user. In 5 or 10 years, you will have them there, available for your use in some eventuality.
"committing build artifacts to the subversion repository" can be a good idea if you know why.
It is a good idea for a release management purpose, more specifically for:
1/ Packaging issue
If a build artifact is not just an exe (or a dll or...), but also:
some configuration files
some scripts to start/stop/restart your artifact
some sql to update your database
some sources (compressed into a file) to facilitate debugging
some documentation (javadoc compressed in a file)
then it is a good idea to have a build artifact and all those associated files stored in a VCS.
(Because it is not anymore just a matter of "re-building" the artifact, but also of "retrieving" all those extra files that will make that artifact run)
2/ Deployment issue
Suppose you need to deploy many artifacts in different environment (test, homologation, pre-production, production).
If:
you produce many build artifacts
those artifacts are quite long to recreate from scratch
then having those artifacts in a VCS is a good idea, in order to avoid recreating them.
You can just query them from environment to environment.
But you need to remember:
1/ you cannot store every artifacts you make in the VCS: all the intermediate build you make for continuous integration purpose must not be stored in the VCS (or you end up with a huge repository with many useless versions of the binaries).
Only the versions needed for homologation and production purposes need to be referenced.
For intermediate build, you need an external repository (maven or a shared directory) in order to publish/test quickly those builds.
2/ you should not store them in the same Subversion Repository, since your development is committed (revision number) much more often than your significant builds (the ones deemed worthy of homologation and production deployment)
That means the artifacts stored in that second repository must have a naming convention for the tag (or for a property) in order to easily retrieve the revision number of the development from which they have been built.
In my experience could storing of Jars in SVN end in a mess.
I think it is better to save the Jar-files in a Maven-Repository like Nexus.
This has also the advantages, that you can use a dependecy managing tool like Maven or Ivy.
Binaries, especially your own, but also third party, have no place in a source control tool like SVN.
Ideally you should have a build scripts to build your own binaries (that can then be automated with one of the many fine automatic build tools that can check the source straight out of SVN).
For third party binaries you will need a dependency management tool like Maven2. You can then set up a local Maven repository to handle all third party binaries (or just rely on the public ones). The local repo can also manage your own binaries.
Putting the binaries in the trunk or branches is definitely overkill. Besides taking up space like you mention, it also leads to inconsistencies between source and binaries. When you refer to revision 1234, you don't want to wonder whether that means "the build resulting from the source at revision 1234" vs "the binaries in revision 1234". The same rule of avoiding inconsistencies applies to auto-generated code. You should not version what can be generated by the build.
OTOH I'm more or less OK with putting binaries in tags. This way it is easy for other projects to use the binaries of other projects via svn:externals, without needing to build all these dependencies. It also enables testers to easily switch between tags without needing a full build environment.
To get binaries in tags, you can use this procedure:
check out a clean working copy
run the build script and evaluate any test results
if the build is OK, svn add the
binaries
instead of committing to the trunk
or branch, tag directly from your
working copy like this: svn copy
myWorkingCopyFolder myTagURL
discard the working copy to avoid
accidental commits of binaries to
the trunk or branch
We have a tagbuild script to semi-automate steps 3 and 4.
One good reason would be to quickly get an executable running on a new machine. In particular if the build environment takes a while to set up. (Load compilers, 3rd party libraries and tools, etc.)
On my projects, I usually have post-build hooks to build from a special working copy on the server, namely in a path reachable from a HTTP browser. That means, after every commit, anyone [who can read the internal web] can easily download the relevant binaries.
No consistency problems, instant updating + a path towards automated testing.
Version control should have everything you need to do: svn co and then build. It shouldn't have intermediates or final product, as that defeats the purpose. You can create a new project in SVN for the result and version the binary result separately (for releases and patches if needed).
Checking in significant binaries violates a usage principle of source code/SVN, namely that files in source control should possess a meaningful property of difference.
Todays source file is meaningfully different to yesterdays source file; a diff will produce a set of changes which make sense to a human reader. Todays picture of the front of the office does not possess a meaningful diff with regard to yesterdays picture of the office.
Because things like images do not possess the concept of difference, WHY are you storing them in a system which exists record and store the differences between files?
Revision based storage is about storing histories of changes to files. There is no meaingful change history in the data of (say) JPEG files. Such files are stored perfectly as well simply in a directory.
More practically, storing large files - build output files - in SVN makes checkout slow. The potential to abuse SVN as a generalised binary repository is there. It all seems fine at first - because there aren't many binary files. Of course, the number of files increases at time passes; I've seen modules which take hours to check out.
It is better to store large associated binary files (and output files) in a directory structure and refer to them from the build process.
Do you mean you have the sources plus the result of the build in the same repository ?
This is a good argument for a daily build, with versioned build scripts in a separate repository. Binary in the repository itself is not bad, but sources + result of build looks bad to me
If you build several binaries and don't notice a build breakage somewhere, then you end up with binaries from different revision, and you are preparing yourself for some subtle bug chase.
Advocate for a daily, separately versioned autobuild script, than just against the binaries + code
Subversion is a Source Control Manager -> Binaries are not source
If you use "svn up" command to update production all developers with commit-permissions can update/modify/broke production?
Alternatives: Use continuous integration like Hudson or Cruise Control.
I think the feeling of having done a bad thing when binary files are comitted to the VCS is reasoned by the basic idea that one should never put redundant things in an archive, reasoned by resource economy and drawbacks of double data management.
That is why: If you can easily reconstruct your archived state of work from the other files of that certain version, like with simple recompiling or installing standard setups, you should not commit such binaries, but rather commit something like a README or INSTALL file. If the difficulties or risk of failing to reconstruct is too much, do commit.

Categories