“The best programmers are all alike; every shitty programmer is shitty in his own special way.” –Anna Karenina
Earlier Your JoeDog mentioned a trait of good programmers. They model data so each element is stored in only one location. This principle is known as a Single Source of Truth. To illustrate that principle, he pointed to siege’s version numbering. The number had to be available in both the program and its helper scripts. In order to uphold SSoT, he stored the number in version.c and parsed that file with a helper script.
Here’s an astonishing fact: not everyone loves the C programming language. Some of you are Java weenies! Fear not, weenies, for you we have another example.
Same problem, different language. We want to store the version number in one location but it must be available for two mechanisms. The first mechanism is the program itself. That’s important, right? It helps answer the question “Which fscking version am I running?” The other mechanism is ant. When we build our jar file we’d like to add the version number to its name, i.e., pinochle-1.0.7.jar.
Let’s examine this is closer detail after the jump.
Still here? good. To solve this problem, we’ll follow the same pattern we used in siege. We’ll set the version number in a place other programmers may expect to find it. A place like — oh, I don’t know — Version.java. Here are the contents of that file:
package org.joedog.pinochle;
public final class Version { public final static String version = "1.0.7"; public final static String copyright = "2011-2015"; public final static String author = "Jeffrey Fulmer, et al."; public final static String email = "[email protected]"; }
To build this package, Your JoeDog used ant. He wanted to create a jar file by typing ‘ant jar’ Simple enough, right? Unfortunately he’s not as refined in ant as he is in autotools. That doesn’t matter. If you take the time to learn programming best practices, it will be easy for you to jump across environments. Best practices are tantamount, the rest is sytax. With clear goal in mind, Your JoeDog was able to construct this solution with some well honed googling.
In his build.xml file, he created a release target that looks like this:
<target name="release"> <loadfile srcfile="${src.dir}/org/joedog/${ant.project.name}/Version.java" property="version"> <filterchain> <linecontainsregexp> <regexp pattern='public final static String version = ".*";'/> </linecontainsregexp> <tokenfilter> <replaceregex pattern='public final static String version = "(.*)";' replace='1'/> <replaceregex pattern=" " replace="" flags="g"/> </tokenfilter> </filterchain> </loadfile> <script language="javascript"> var version = project.getProperty("version"); project.setProperty("version", version.replaceAll("n", "")); </script> <echo>"${version}"</echo> </target>
This target reads Version.java and parses the release number (in this case 1.0.7). It then assigns that number to an ant property named version. You can access its value like this: ${version}. Cool, huh? So now we can build our jar file:
<target name="jar" depends="release,clean,compile,resources"> <jar jarfile="${dist.dir}/${ant.project.name}-${version}.jar" basedir="${build.dir}"> <manifest> <!-- snipped for brevity for details see the build.xml file https://github.com/JoeDog/pinochle/blob/master/build.xml --> </manifest> </jar> </target>
Certainly there’s more than one way to hump that leg, but this mechanism works well at JoeDog Industries. It may even work well for you. The main take-away is this: If you have more than one copy of a data source, then you’re doing something wrong. Copy-paste is evil. Redundant typing is eviler.
Happy hacking.