tag:blogger.com,1999:blog-344095292024-02-20T22:10:34.740+00:00Nuno Sousa's CornerNuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.comBlogger69125tag:blogger.com,1999:blog-34409529.post-21354085409608707692011-10-05T12:41:00.000+01:002011-10-05T12:41:12.000+01:00OpenClock and Gentoo<a href="http://www.openclonk.org/">OpenClonk</a> is an open source game that has been in development for some time. Its fun and free.<br />
<br />
I downloaded a binary some time ago and started using it, but the latest release just doesn't work on my <a href="http://www.gentoo.org/">Gentoo</a> machine in binary form. After some digging I didn't found an ebuild for this release, just for the live version. So I wrote my own and added to <a href="https://bugs.gentoo.org/show_bug.cgi?id=348149">Gentoo's bug database</a>.<br />
<br />
I learned a few things along the way but didn't get it as clean as I wanted. If someone knows how to convince cmake to install to a different directory than the prefix used it would be great. I ended up doing a patch for the generated <i>cmake_install.cmake</i>. If anyone knows how to avoid that patch I would appreciate the help.<br />
<br />
Here is a preview of the game:<br />
<center><iframe width="420" height="315" src="http://www.youtube.com/embed/zydiZSXpn0w" frameborder="0" allowfullscreen></iframe></center>Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-11956572425602232582011-04-05T17:58:00.002+01:002011-04-05T18:07:33.485+01:00Hidden Features...I bought a Samsung SyncMaster XL2370HD recently. It has more than what I needed but I couldn't find one without the features I didn't need (HDTV) for a cheaper price so I bought it.<br /><br />I honestly though about returning it because the colours and fonts were horrible when I first connected my laptop through HDMI. I played a <span style="font-weight:bold;">LOT</span> with the settings but didn't get anything good. I finally solved the issue by renaming the source.<br /><br />That's right: you go the options, rename the source HDMI to PC and everything should start to working perfectly. They should call this feature "Source Fixer" instead of "Name Editor" as it turns off many of the "default" processing features that I don't need.<br /><br />So, if you had a problem with weird colours or fonts in your monitor when using an HDMI cable try to rename the source HDMI. It is called "Edit Name" in my monitor and it will show you a list of devices (it won't allow you to input one). Just choose PC and it will work.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-12741528778918800712011-01-20T09:47:00.001+00:002011-10-05T12:56:49.947+01:00More on Jack...Well, jack isn't working well with non jack applications. The jack-plug doesn't always work and I can't get it to be stable. I'll continue to look into it. If I find anything I'll post it here. For now I'll use jack with applications that support jack.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-74054938436762886772011-01-19T11:51:00.002+00:002011-01-19T12:00:16.663+00:00Enhanced security in ChromiumI moved away from <a href="http://www.mozilla.com/en-US/firefox/">Firefox</a> to <a href="http://code.google.com/chromium/">Chromium</a> (the open source part of <a href="http://www.google.com/chrome">Google Chrome</a>). When I moved I search for all the extensions I used in Firefox. One of them was <a href="https://addons.mozilla.org/en-US/firefox/addon/flashblock/">Flashblock</a>. There is also a <a href="https://chrome.google.com/extensions/detail/gofhjkjmkpinhpoiabjplobcaignabnl">Flashblock for Google Chrome</a> but I wanted to block all plugins until I say so.<br /><br />Luckily, Google Chrome has that option. Just got to <a href="about:flags">about:flags</a> and enable on the Click to Play flag (this is available in the latest beta of Google Chrome 9, I don't know about the stable Google Chrome 8). Restart the Browser so the flag comes into use. Then enable click to play for the plugins as follows: Open the Preferences, go to "Under the Hood", Right under the "Privacy" click the button "Content Settings...". Then select "Plug-ins" and choose the brand new "Click to play" option.<br /><br />When you open pages with plugins an icon will appear in the address bar indicating that plugins were blocked. You can use the icon and enable all the plugins for the page, but I prefer the Click to Play: Google Chrome will put a gray area with a large puzzle peace icon on it. When you hover the mouse on it the mouse changes and an indication appears saying "Click to run this plug-in" with the name of the plug-in under it. If you want just click it. You can also you the icon on the address bar to always allow plugins on certain domains (like <a href="http://www.youtube.com/">Youtube</a>).Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-31298630180355377652011-01-19T11:28:00.005+00:002011-10-05T12:57:03.337+01:00Using jack to record telcos and screenAt my job we use <a href="http://en.wikipedia.org/wiki/Voice_over_IP">VOIP</a> regularly when making conferences or simply calling a colleague. We also have a screen sharing tool that we use to share the screen to remote participants. This is also used to make remote training sessions. What I've been missing is a way to record both the shared screen and sound for later viewing. I hacked jack a little in the past but didn't manage to get it working. I've been having some free time so I decided to hack it today and I finally got it working. So, from the start.<br />
<br />
Gentoo's <a href="http://en.gentoo-wiki.com/wiki/JACK">JACK guide on the wiki</a> is not bad but I honestly didn't pay much attention to it. I have the <i>jack</i> use flag enabled globally so it was time to get it going.<br />
<br />
First I emerged <a href="http://qjackctl.sourceforge.net/">qjackctl</a>. It is nice program that sits on the tray area (I have it default to hidden) that starts the jack daemon and that allows you to control what is connected to where. I also emerged alsa-plugins to get the alsa-jack plugin. Finally I emerge <a href="http://jamin.sourceforge.net/">jamin</a>. I need it just to be able to get the output back in :-)<br />
<br />
I configured also to use the jack plug by default. This can be done by creating a ".asoundrc" file in your home folder with the following content:<br />
<pre>pcm.!default {
type plug
slave { pcm "jack" }
}
pcm.jack {
type jack
playback_ports {
0 system:playback_1
1 system:playback_2
}
capture_ports {
0 system:capture_1
1 system:capture_2
}
}</pre>
I also keep a ".asound_nojack" file that has the jackplug but doesn't turn it to the default audio output for alsa.<br />
<pre>pcm.jackplug {
type plug
slave { pcm "jack" }
}
pcm.jack {
type jack
playback_ports {
0 system:playback_1
1 system:playback_2
}
capture_ports {
0 system:capture_1
1 system:capture_2
}
}</pre>
With that in place any application that does not support jack but support alsa will still work.<br />
<br />
qjackctl has <a href="http://qjackctl.sourceforge.net/qjackctl-ss1.html">several windows</a>, one of them is the Connections. I use it to reroute sound before recording.<br />
<br />
What I do is start jamin, redirect all the bits I want to record to jasmin and disconnect them from the system output. Then start <a href="http://recordmydesktop.sourceforge.net/">qt-recordmydesktop</a> and point it to use the jamin output as audio source when recording. Here are screenshots of the important bits.<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYzJV3eEQOt2YG-fcRVL-2rVzjdqB_ggmOPf_VriHfpDmRII66x2LJhosROVJmYRZ9M6lAmctN_G3o_kqgbR03MnhxFHQES3_VVermPhLGRS3jo_5D7IimgEDRoP42WlJ4f0AMog/s1600/Connections.png"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5563862730978619490" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYzJV3eEQOt2YG-fcRVL-2rVzjdqB_ggmOPf_VriHfpDmRII66x2LJhosROVJmYRZ9M6lAmctN_G3o_kqgbR03MnhxFHQES3_VVermPhLGRS3jo_5D7IimgEDRoP42WlJ4f0AMog/s320/Connections.png" style="cursor: hand; cursor: pointer; display: block; height: 163px; margin: 0px auto 10px; text-align: center; width: 320px;" /></a><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaZzVo1FGlTxJVhQrAeqB2_wAxQ1XrNdjue6jJNP7-zsn8MySWnFWuH6aklF9RdRZdVHbPhKNZgQ6jo1e8DjY8FSwTDMGayY6EDPjCZbvGY6JoazVe1QzNK8mQYmb_o4zK0UqocQ/s1600/RecordMyDesktop.png"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5563862984623823538" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaZzVo1FGlTxJVhQrAeqB2_wAxQ1XrNdjue6jJNP7-zsn8MySWnFWuH6aklF9RdRZdVHbPhKNZgQ6jo1e8DjY8FSwTDMGayY6EDPjCZbvGY6JoazVe1QzNK8mQYmb_o4zK0UqocQ/s320/RecordMyDesktop.png" style="cursor: hand; cursor: pointer; display: block; height: 320px; margin: 0px auto 10px; text-align: center; width: 175px;" /></a><br />
<b>Importante Note:</b> <a href="http://recordmydesktop.sourceforge.net/">recordmydesktop</a> has a bug that makes it complain that it has no jack support, even though the use flag is turned on. This is <a href="http://bugs.gentoo.org/283489">fixed upstream</a> and available in Gentoo as a backport but you will have to unmask the package (0.3.8.1-r4 works at the time I wrote this).<br />
<br />
<b>NOTE:</b> This isn't working very well... see <a href="http://nuno-sousa-corner.blogspot.com/2011/01/more-on-jack.html">here</a>Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-32356910064790260122010-12-29T17:59:00.002+00:002011-10-05T12:57:23.115+01:00Howto make your private VM Cluster, Part IIIContinuing with my <a href="http://nuno-sousa-corner.blogspot.com/2010/12/howto-make-your-private-vm-cluster-part_29.html">saga</a>, next up is <a href="http://www.drbd.org/">DRBD</a>. I'm using DRBD because I also want to test it as a viable alternative for <i>network raid</i>.<br />
<br />
To use DRBD I first created a LVM volume to use:<br />
<pre>lvcreate -n drbd-demo -L 100M internal-hd</pre>
Then I configured DRBD on both nodes, fortunately gentoo simplifies a great part of the process (you have to do this on <b>both</b> nodes):<br />
<pre>cd /etc
cp /usr/share/doc/drbd-*/drbd.conf.bz2 .
bunzip2 drbd.conf.bz2</pre>
Then I created a wwwdata resource by first configuring it (again on <b>both</b> nodes). This is done by creating a file /etc/drbd.d/wwwdata.res with the contents:<br />
<pre>resource wwwdata {
meta-disk internal;
device /dev/drbd1;
syncer {
verify-alg sha1;
}
net {
allow-two-primaries;
}
on node1 {
disk /dev/mapper/internalhd-drbd--demo;
address 192.168.100.10:7789;
}
on node2 {
disk /dev/mapper/internalhd-drbd--demo;
address 192.168.100.11:7789;
}
}</pre>
I added the drbd module to the /etc/modules.autoload.d/kernel-2.6 on both nodes.<br />
<br />
Finally I started drbd on node 1 as follows:<br />
<pre>drbdadm create-md www-data
modprobe drbd
drbdadm up wwwdata</pre>
And on node 2 as follows:<br />
<pre>drbdadm --force create-md www-data
modprobe drbd
drbdadm up wwwdata</pre>
I then used node 1 as reference for the data:<br />
<pre>drbdadm -- --overwrite-data-of-peer primary wwwdata</pre>
I monitored the sync process until it was completed with:<br />
<pre>watch cat /proc/drbd</pre>
When completed I created the file system and populated it with an index.html file indicating the cluster:<br />
<pre>mkfs.ext4 /dev/drbd1
mount /dev/drbd1 /mnt
# Create a index.html
umount /dev/drbd1</pre>
I configured the cluster to use drbd as follows (this will enter the crm shell but don't panic):<br />
<pre>crm
cib new drbd
configure primitive WebData ocf:linbit:drbd params drbd_resource=wwwdata op monitor interval=30s
configure ms WebDataClone WebData meta master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true
cib commit drbd
quit</pre>
After this I configured a WebFS service so the lighttpd will serve from the DRBD mounted volume.<br />
<pre>crm
cib new webfs
configure primitive WebFS ocf:heartbeat:Filesystem params device="/dev/drbd/by-res/wwwdata" directory="/var/www/localhost/htdocs" fstype="ext4"
configure colocation WebFS-on-WebData inf: WebFS WebDataClone:Master
configure order WebFS-after-WebData inf: WebDataClone:promote WebFS:start
configure colocation WebSite-with-WebFS inf: WebSite WebFS
configure order WebSite-after-WebFS inf: WebFS WebSite
cib commit webfs
quit</pre>
After this, if you go to your cluster web page (http://192.168.100.20) you will see the contents of the index.html that you created for the cluster.<br />
<br />
You can use "crm_mon" to monitor the cluster and look at /var/log/message to view error messages. To simulate a full service relocation go the the node were the services are running and issue "crm node standby" this will put the current node on standby forcing the services to be moved to the other node. After that you can do "crm node online" to bring the node back online.<br />
<br />
This concludes this series. Maybe I'll put up another on to have nfs use the drbd, depends on free time.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-73071472970902935112010-12-29T17:26:00.003+00:002011-10-05T12:57:14.908+01:00Howto make your private VM Cluster, Part IIIn the <a href="http://nuno-sousa-corner.blogspot.com/2010/12/howto-make-your-private-vm-cluster-part.html">previous entry</a> I showed how to build the basic structure for your own private VM Cluster. Today I'm going to show you how to create a cluster with two VMs that provides High-Availability for a WebServer using <a href="http://www.drbd.org/">DRBD</a> to replicate the Web Site.<br />
<br />
First you need to create a virtual machine. I decided to create a VM with <a href="http://www.gentoo.org/">Gentoo</a>. I will use LVM to keep the partition to use for drbd small since this is a simple test.<br />
<br />
I created a qemu-img for a base gentoo installation (my goal is to install gentoo on the VM and then reuse it as base for the other VMs). To create the image just run:<br />
<pre>qemu-img create -f qcow2 gentoo.qcow2 10G</pre>
I started the VM using that image and followed <a href="http://www.gentoo.org/doc/en/handbook/handbook-x86.xml"> Gentoo's installation guide</a>. My partition scheme was 100Mb (boot), 512Mb (swap), 5Gb (root), rest for lvm.<br />
<br />
I used the gentoo-sources, configuring all virtio devices, drbd and the device-mapper. I configured genkernel to use lvm so it detects the lvm volumes at boot. I used grub and added all the genkernel options.<br />
<br />
Remember that if you use the minimal installation CD the hard disk will be called sda but after setting up virtio in the kernel it will be called vda. I created a generic startvm script that will provide the disk and network card using virtio. I called it startVM: <br />
<pre style="background-color: black; color: white;"><span style="color: orangered;">#</span><span style="color: orangered;">!/bin/</span><span style="color: cyan;">bash</span><span style="color: orangered;">
</span><span style="color: lightsteelblue;">set</span> -x
<span style="color: cyan;">if</span> [[ $# != 2 && $# != 3 ]]; <span style="color: cyan;">then</span>
<span style="color: lightsteelblue;">echo</span> <span style="color: lightsalmon;">"Usage: startVM <mac> <hda> [cdrom]"</span>
<span style="color: cyan;">exit</span> 1
<span style="color: cyan;">fi</span>
<span style="color: orangered;"># </span><span style="color: orangered;">Get the location of the script</span><span style="color: #eedd82;">SCRIPT</span>=<span style="color: salmon;">`readlink -f $0`</span>
<span style="color: #eedd82;">SCRIPT_PATH</span>=<span style="color: salmon;">`dirname $SCRIPT`</span>
<span style="color: orangered;"># </span><span style="color: orangered;">Create tap interface so that the script /etc/qemu-ifup can bridge it</span><span style="color: orangered;"># </span><span style="color: orangered;">before qemu starts</span><span style="color: #eedd82;">USERID</span>=<span style="color: salmon;">`whoami`</span>
<span style="color: #eedd82;">IFACE</span>=<span style="color: salmon;">`sudo tunctl -b -u $USERID`</span>
<span style="color: orangered;"># </span><span style="color: orangered;">Setup KVM parameters</span><span style="color: #eedd82;">CPUS</span>=<span style="color: lightsalmon;">"-smp 8"</span>
<span style="color: #eedd82;">MEMORY</span>=<span style="color: lightsalmon;">"-m 1G"</span>
<span style="color: #eedd82;">MACADDRESS</span>=$<span style="color: #eedd82;">1</span>
<span style="color: #eedd82;">HDA</span>=$<span style="color: #eedd82;">2</span>
<span style="color: cyan;">if</span> [[ $# == 3 ]]; <span style="color: cyan;">then</span>
<span style="color: #eedd82;">CDROM</span>=<span style="color: lightsalmon;">"-cdrom $3"</span>
<span style="color: cyan;">else</span>
<span style="color: #eedd82;">CDROM</span>=<span style="color: lightsalmon;">""</span>
<span style="color: cyan;">fi</span>
<span style="color: #eedd82;">NET</span>=<span style="color: lightsalmon;">"-net nic -net tap,script=/etc/qemu-ifup"</span>
<span style="color: orangered;"># </span><span style="color: orangered;">Start kvm</span>kvm $<span style="color: #eedd82;">CPUS</span> $<span style="color: #eedd82;">MEMORY</span> -drive <span style="color: #eedd82;">file</span>=$<span style="color: #eedd82;">HDA</span>,<span style="color: #eedd82;">if</span>=virtio,<span style="color: #eedd82;">boot</span>=on $<span style="color: #eedd82;">CDROM</span> -net nic,<span style="color: #eedd82;">model</span>=virtio,<span style="color: #eedd82;">macaddr</span>=$<span style="color: #eedd82;">MACADDRESS</span> -net tap,<span style="color: #eedd82;">ifname</span>=$<span style="color: #eedd82;">IFACE</span>,<span style="color: #eedd82;">script</span>=$<span style="color: #eedd82;">SCRIPT_PATH</span>/qemu-ifup
<span style="color: orangered;"># </span><span style="color: orangered;">kvm has stopped - remove tap tap interface</span>sudo tunctl -d $<span style="color: #eedd82;">IFACE</span> &> /dev/null</pre>
After successfully booting to the Gentoo VM I halted the VM to create another disk image. I may want to reuse this vanilla Gentoo VM in the future so I created another disk image taking this vanilla one as base as follows:<br />
<pre>qemu-img create -f qcow2 -o backing_file=gentoo.qcow2 gentoo-drbd.qcow2</pre>
Then I started the VM with the new script with: <br />
<pre>startVM DE:AD:BE:EF:E3:1D gentoo-drbd.qcow2</pre>
The MAC Address will be important later.<br />
<br />
Now I installed all the packages that I will be needing for each node in the cluster. The goal is to avoid having to build them many times and to reuse this image for all nodes. Basic steps are as follows: <br />
<pre>emerge -av telnet-bsd drbd lvm2 pacemaker lighttpd
eselect python set python2.6
pvcreate /dev/vda4
vgcreate internalhd /dev/vda4</pre>
I changed python to 2.6 because pacemaker requires it. I added the following to /etc/hosts to avoid doing it everyware:<br />
<pre>
192.168.100.10 node1
192.168.100.11 node2
192.168.100.20 cluster</pre>
Next I created an image for the two nodes as follows:<br />
<pre>qemu-img create -f qcow2 -o backing_file=gentoo-drbd.qcow2 gentoo-drbd-node1.qcow2
cp gentoo-drbd-node1.qcow2 gentoo-drbd-node2.qcow2</pre>
Then I created to scripts, one to start each VM. The contents are as follows (for node2 you <b>must</b> change the mac address): <br />
<pre style="background-color: black; color: white;"><span style="color: orangered;">#</span><span style="color: orangered;">!/bin/</span><span style="color: cyan;">bash</span><span style="color: orangered;">
</span><span style="color: lightsteelblue;">set</span> -x
<span style="color: orangered;"># </span><span style="color: orangered;">Get the location of the script</span><span style="color: #eedd82;">SCRIPT</span>=<span style="color: salmon;">`readlink -f $0`</span>
<span style="color: #eedd82;">SCRIPT_PATH</span>=<span style="color: salmon;">`dirname $SCRIPT`</span>
startVM DE:AD:BE:EF:E3:1D gentoo-drbd-node1.qcow2</pre>
I then configured static IPs for each node, that is: edit /etc/conf.d/hostname to be either node1 or node2 and the contents of /etc/conf.d/net to be:<br />
<pre>config_eth0=( "192.168.100.10/24" )
routes_eth0=( "default via 192.168.100.1" )</pre>
For node 2 the IP ends in 11. Next I confired corosync. This must be done on both nodes:<br />
<pre>cd /etc/corosync
cp corosync.conf.example to corosync.conf</pre>
Edit the corosync.conf file and make the bindnetaddr be the IP address of the node. And add the pacemaker service by adding the following to the end of the file:<br />
<pre>service {
name: pacemaker
ver: 0
}</pre>
I started corosync on both nodes and marked it to start on boot:<br />
<pre>/etc/init.d/corosync start
rc-update add corosync default</pre>
Then I proceded to congiure the cluster. First I turned of <a href="http://en.wikipedia.org/wiki/STONITH">STONITH</a>:<br />
<pre>crm configure property stonith-enabled=false</pre>
Then I created the Virtual IP for the Cluster:<br />
<pre>crm configure primitive ClusterIP ocf:hertbeat:IPaddr2 params ip=192.168.100.20 cidr_netmask=32 op monitor interval=30s</pre>
Marked the cluster to runt with two nodes (without quorom, please don't discuss this in the comments) and for resource stickiness (to avoid having the resources move around if not needed):<br />
<pre>crm configure property no-quorum-policy=ignore
crm configure rsc_defaults resource-stickiness=100</pre>
I added lighttpd as a service. First I created index.html on both nodes and different so that I can check if things are working. Next I created the service in the cluster: <br />
<pre>crm configure primtive WebSite lsb:lighttpd op monitor interval=30s
crm configure colocation website-with-ip INFINITY: WebSite ClusterIP
crm configure order lighttpd-after-ip mandatory: ClusterIP WebSite</pre>
<br />
You can test and access the cluster address (http://192.168.100.20) to see whose answering. You can stop the corosync service to view the service migrate between nodes.<br />
<br />
Next up DRBD.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-87778398292025664082010-12-28T12:22:00.004+00:002010-12-28T22:06:26.517+00:00Howto make your private VM Cluster, Part II wanted to make some experiments with <a href="http://www.drbd.org/">DRBD</a>, <a href="http://www.linux-ha.org/wiki/Pacemaker">pacemaker</a> and others. The goal is to test a few configurations for an high availability scenario. Since I don't want to make changes to my machine the solution is to use Virtual Machines. I decided to go all open source and use <a href="http://www.linux-kvm.org/">KVM</a>. Since I want more that a single VM I decided to setup a private bridge to which all the VMs would connect. The bridge would provide DHCP and DNS services and NAT + Firewall to the internet.<br /><br />I use <a href="http://www.gentoo.org/">Gentoo</a>. If you use another distribution or firewall tool you should adapt these instructions and scripts to fit your needs.<br /><br />First I created a script that sets up my bridge. The script is as follows (I called it setupBridge):<pre style="color: #ffffff; background-color: #000000;"><span style="color: #ff4500;">#</span><span style="color: #ff4500;">!/bin/</span><span style="color: #00ffff;">bash</span><span style="color: #ff4500;"><br /></span><span style="color: #b0c4de;">set</span> -x<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Setup the bridge<br /></span>sudo brctl addbr br0<br />sudo ifconfig br0 192.168.100.1 netmask 255.255.255.0 up<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Launch DNS and DHCP Server on br0<br /></span>sudo dnsmasq -q -a 192.168.100.1 --dhcp-range=192.168.100.50,192.168.100.150,forever --pid-file=/tmp/br0-dnsmasq.pid<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Launch updated firewall configuration<br /></span>sudo firehol /home/nsousa/KVM/firehol-br0.conf start</pre>The bridge is created and I give it the 192.168.100.1 ip address. I use dnsmasq to provide DNS and DHCP. The DHCP provided addresses will be from 192.168.100.50 to 150. Finally I adapt the firewall using <a href="http://firehol.sourceforge.net/">firehol</a>. Here is the firehold configuration file (firehol-br0.conf): <pre style="color: #ffffff; background-color: #000000;"><span style="color: #eedd82;">version</span> 5<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Allow all traffic in the Bridge<br /></span><span style="color: #eedd82;">interface</span> br0 bridge<br /> <span style="color: #eedd82;">server</span> all accept<br /> <span style="color: #eedd82;">client</span> all accept<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Accept all client traffic on any interface<br /></span><span style="color: #eedd82;">interface</span> any world<br /> <span style="color: #eedd82;">client</span> all accept<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">NAT to the internet<br /></span><span style="color: #eedd82;">router</span> bridge2internet inface eth0 outface br0<br /> <span style="color: #eedd82;">masquerade</span> reverse<br /> <span style="color: #eedd82;">client</span> all accept<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Bridge Routing<br /></span><span style="color: #eedd82;">router</span> bridge-routing inface br0 outface br0<br /> <span style="color: #eedd82;">server</span> all accept<br /> <span style="color: #eedd82;">client</span> all accept<br /></pre>This basically allows the VMs to connect to any service running on br0 (the host). It allows any one to connect to anyone as client (so the host can go to the internet). Finally it sets up NAT using masquerade so the VMs can use the bridge to access the internet, but as clients only.<br /><br />To undo all these changes I have a script that tears all this setup down. I called it teardownBridge and here are its contents: <pre style="color: #ffffff; background-color: #000000;"><span style="color: #ff4500;">#</span><span style="color: #ff4500;">!/bin/</span><span style="color: #00ffff;">bash</span><span style="color: #ff4500;"><br /></span><span style="color: #b0c4de;">set</span> -x<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Stop DHCP and DNS Server<br /></span>sudo kill -15 <span style="color: #fa8072;">`cat /tmp/br0-dnsmasq.pid`</span><br />sudo rm /tmp/br0-dnsmasq.pid<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Stop the bridge<br /></span>sudo ifconfig br0 down<br />sudo brctl delbr br0<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Reset the firewall<br /></span>sudo firehol /etc/firehol/firehol.conf start<br /></pre>Before moving to the script that starts one VM I first need to show the script that sets up the interface for qemu to use (I called it qemu-ifup): <pre style="color: #ffffff; background-color: #000000;"><span style="color: #ff4500;">#</span><span style="color: #ff4500;">!/bin/</span><span style="color: #00ffff;">bash</span><span style="color: #ff4500;"><br /></span><span style="color: #b0c4de;">set</span> -x<br /><br /><span style="color: #00ffff;">if </span><span style="color: #b0c4de;">test</span> $(<span style="color: #fa8072;">/sbin/ifconfig</span> | grep -c $<span style="color: #eedd82;">1</span>) -gt 0; <span style="color: #00ffff;">then</span><br /> sudo /sbin/brctl delif br0 $<span style="color: #eedd82;">1</span><br /> sudo /sbin/ifconfig $<span style="color: #eedd82;">1</span> down<br /><span style="color: #00ffff;">fi</span><br /><br />sudo /sbin/ifconfig $<span style="color: #eedd82;">1</span> 0.0.0.0 promisc up<br />sudo /sbin/brctl addif br0 $<span style="color: #eedd82;">1</span><br /></pre> The goal here is to add the tap device created to the bridge. I first remove it if it is already there.<br /><br />Last but not least the script that starts a VM. This script sets up a tap device for the current user, configures KVM start-up parameters and starts KVM. When KVM ends it removes the tap device to keep the system clean. Here is the contents of the script adapted to use a hard disk and the minimal install cd for gentoo (I called it startVM): <pre style="color: #ffffff; background-color: #000000;"><span style="color: #ff4500;">#</span><span style="color: #ff4500;">!/bin/</span><span style="color: #00ffff;">bash</span><span style="color: #ff4500;"><br /></span><span style="color: #b0c4de;">set</span> -x<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Create tap interface so that the script /etc/qemu-ifup can bridge it<br /></span><span style="color: #ff4500;"># </span><span style="color: #ff4500;">before qemu starts<br /></span><span style="color: #eedd82;">USERID</span>=<span style="color: #fa8072;">`whoami`</span><br /><span style="color: #eedd82;">IFACE</span>=<span style="color: #fa8072;">`sudo tunctl -b -u $USERID`</span><br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Setup KVM parameters<br /></span><span style="color: #eedd82;">MEMORY</span>=<span style="color: #ffa07a;">"-m 512"</span><br /><span style="color: #eedd82;">IMGPATH</span>=<span style="color: #ffa07a;">"/home/nsousa/KVM"</span><br /><span style="color: #eedd82;">IMAGE</span>=gentoo.qcow2<br /><span style="color: #eedd82;">CDROM</span>=<span style="color: #ffa07a;">"-cdrom /home/nsousa/Downloads/install-x86-minimal-20101123.iso"</span><br /><span style="color: #eedd82;">MACADDRESS</span>=<span style="color: #ffa07a;">"DE:AD:BE:EF:5D:A3"</span><br /><span style="color: #eedd82;">NET</span>=<span style="color: #ffa07a;">"-net nic -net tap,script=/etc/qemu-ifup"</span><br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">Start kvm<br /></span>kvm $<span style="color: #eedd82;">MEMORY</span> -hda $<span style="color: #eedd82;">IMGPATH</span>/$<span style="color: #eedd82;">IMAGE</span> $<span style="color: #eedd82;">CDROM</span> -net nic,<span style="color: #eedd82;">macaddr</span>=$<span style="color: #eedd82;">MACADDRESS</span> -net tap,<span style="color: #eedd82;">ifname</span>=$<span style="color: #eedd82;">IFACE</span>,<span style="color: #eedd82;">script</span>=/home/nsousa/KVM/qemu-ifup<br /><br /><span style="color: #ff4500;"># </span><span style="color: #ff4500;">kvm has stopped - remove tap tap interface<br /></span>sudo tunctl -d $<span style="color: #eedd82;">IFACE</span> &> /dev/null<br /></pre>Next step is to make a minimal gentoo installation on a VM to use as base for all the VMs in the cluster. I'll probably refactor the startVM script to separate the common parts (the private parts will be the disk image to use and MAC Address).<br /><br />Stay tuned for more updates.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-39662572925428753562010-09-15T21:52:00.003+01:002010-09-15T22:03:07.064+01:00Laptop Power SavingToday I had an issue updating the kernel on my company's laptop. I ended up reconfiguring it from strach istead of doing the oldconfig option (make oldconfig didn't ask anything but the kernel hard locked on boot). I took the oportunity to try to get a more duration out of the battery. How? By consuming less power.<br /><br /><a href="http://www.lesswatts.org/projects/powertop/">PowerTop</a> came in and lend a helping hand but it was not sufficient. When I enabled USB Suspend (CONFIG_USB_SUSPEND) the keyboard didn't work well. I have a keyboard, mouse and webcam connected to a hub that I use when I'm on my desk. Everything was working, power was being saving, even for the keyboard. The problem was that when the keyboard entered power saving mode and I pressed a key the first key that I pressed would be lost. The <a href="http://www.mjmwired.net/kernel/Documentation/usb/power-management.txt#243">documentation</a> talks about this issue but I didn't want to loose on the opportunity to increase my laptop's autonomy. Solution: udev to the rescue.<br /><br />I created a udev rule that detects the USB Keyboard (by vendor and product id, maybe someday I'll connect to a keyboard without a problem). When the keyboard is connect it disables auto suspend just for the keyboard. Here is how I've done it (<i>Note</i>:I'm using Gentoo, but this should work on any linux, with more or less salt).<br /><br />I created a udev rule in "/etc/udev/rules.d/92-usb-autosuspendfix.rules" with the following contents:<pre>SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0403",<br /> RUN+="/etc/fixes/disableKeyBoardAutoSuspend.sh 04f2 0403"</pre>The "/etc/fixes/disableKeyBoardAutoSuspend.sh" script does the whole magic. It search for the usb device in the sysfs and toggles the power control to on (it defaults to auto if the device supports power control).<pre>#!/bin/bash<br /><br />cd /sys/bus/usb/devices/<br />for device in `ls`; do<br /> if [ -f $device/idVendor ]; then<br /> if [ -f $device/idProduct ]; then<br /> vendor=`cat $device/idVendor`<br /> product=`cat $device/idProduct`<br /> if [ "$1 $2" == "$vendor $product" ]; then<br /> echo "Disable power for device $vendor:$product."<br /> cd $device/power<br /> echo on > level<br /> fi<br /> fi<br /> fi<br />done</pre>Hope this helps you. Maybe we should start a blacklist of USB devices that don't work well with power control.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-49051044301807967392010-09-10T12:45:00.002+01:002010-09-10T12:47:20.161+01:00When hackers have fun!Today I was building the RRDTool from source and I noticed the output of the configuration part was ordering a CD.<pre>config.status: executing po-directories commands<br />config.status: creating po/POTFILES<br />config.status: creating po/Makefile<br />config.status: executing default commands<br />checking in... and out again<br />ordering CD from http://tobi.oetiker.ch/wish .... just kidding ;-)<br /><br />----------------------------------------------------------------<br />Config is DONE!<br /></pre>This shows that hackers love to play ;-)Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-74075526759335292132010-05-08T15:22:00.001+01:002010-05-08T15:24:03.027+01:00A new LaptopI just got a bran new Sony Vaio VPCF11Z1E as part of a compensation of making the b2b web site for my family's company. It comes preloaded with Windows 7 that I intend to leave there just in case. I'll put any special instruction on getting it running with Gentoo, my Linux distribution of choice, but first I like to talk about the hands on experience with such a computer.<br /><br />I decided to turn it on and let Windows 7 do its thing. After all, it has 500Gb of disk space and the goal is to replace my old broken laptop that served me for almost 10 years and that one had a 80Gb hard disk. So, if I leave windows with 100 Gb of disk space it should be more than sufficient.<br /><br />After turning on the PC I decided to follow the guideline and let windows and Sony's update tools run. It took an amazing 4 hours to download and install everything. I have an ADSL connection that could do 24Mbit/s but since I'm far away from the phone box it only does 8Mbit/s. What Amazed me is that just for Sony's updates it had to download almost 1Gb of data. I mean, it is a brand new laptop couldn't be updated already?<br /><br />After all these updates I decided I should also create the recovery disks. You see, way back when I bought my old laptop it came with recovery disks, recovery disks and a whole lot more things. Today the laptops don't have recovery disks but recovery partitions. The disks you have to create them your self (another 2 ours to the mix) or to order and pay for them.<br /><br />I call this a bad user experience. I brand new top of the line computer and I needed to go by 4 dvds and invest over 6 hours just to get it to a point that it is ready for usage if you follow the guidelines.<br /><br />On top of that these people are getting more stupid every day. I was going to use windows disk management tool to shrink the windows partition to say 100Gb and I found out some nice gems. First the recovery partition is in the beginning of the disk. I though the faster part of the hard drive was its beginning, but I must be wrong, the Internet and all those that discuss there must also be wrong. You see, someone at Sony decided to put the recovery partition in the beginning of the drive. Strange because all laptops I saw until today had this partition at the end of the hard drive. To make things worse there is another 100Mb partition after that one and then comes the rest of the disk. What is the 100Mb partition used for? Well, it is called the System Rescue partition and it is the one with the boot flag. I assume this has the software Sony uses to recover the computer.<br /><br />To culminate my disappointment windows is reporting that it can only shrink the partition to 244G. I'll try shrinking it, then defrag it and then shrinking it again. If it doesn't work it seems I'll be putting the recovery partition to the test because I'm going to delete the partition and use the recovery to get windows to use only 100G or so. I mean, it has 49Gb of used disk space and it is a clean install with updates. What the hell is this thing doing? And 49Gb just for the operating system with a browser, demo of Office an little more? That is more than bloat!Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com1tag:blogger.com,1999:blog-34409529.post-69087650491432095252010-04-13T22:28:00.003+01:002011-10-05T12:59:02.931+01:00GWT Part II: From Ant to MavenIn the <a href="/2010/04/gwt-start-up-improving-ant-build-file.html">last entry</a> I showed how to get started with GWT and get a nicer build file with Ant. In this entry I'll explain the process of moving from Ant to Maven.<br /><br />My goal here is to take advantage of all of Maven's features while still maintaining a workable project configuration that I can use from a command line and from Eclipse. GWT's tools generate an Eclipse project but don't do other things like, for instance, adding dependencies to the Eclipse project when you add them to the build file. Maybe you can do this using Apache's <a href="http://ant.apache.org/ivy/">Ivy</a>. I haven't tried it, maybe I will someday if I end up hitting a wall using Maven...<br /><br />First thing to do is to rearrange our source code. Maven expects things to be on different paths and we will have to do that. I started by moving all java source code to a newly created "src/main/java". I'm using git so I just did:<pre>$ mkdir -p src/main/java<br />$ git mv src/org src/main/java/org<br /></pre>I had to do a similar step for the unit tests:<pre>$ mkdir -p src/test/java<br />$ git mv test/org src/test/java<br />$ rmdir test<br /></pre> Finally I had to move the war file to the folder maven expects the WAR resources to be int. It is also a simple move operation:<pre>$ mkdir -p src/main/webapp<br />$ git mv war/* src/main/webapp/<br />$ rmdir war<br />$ git rm -f src/main/webapp/WEB-INF/lib/gwt-servlet.jar<br /></pre>I also removed the <i>gwt-servlet.jar</i> file that was added by the GWT tools as maven will take care of it for me.<br /><br />Maven supports resources and resource filtering but GWT has special needs. This means that GWT's XML files for the source code need to reside on the same code as the java files, something that is not usual in Maven projects. But I had to do this for the test resources, that is, for the GWT xml file used in the tests. That was relatively simple:<pre>$ mkdir -p src/test/resources/org/nuno/backoffice<br />$ git mv src/test/java/org/nuno/backoffice/BackOfficeJUnit.gwt.xml src/test/resources/org/nuno/backoffice</pre>But this is not sufficient. The naming convention for unit tests are different. We want to support plain old unit tests and GWT Test Cases. For Maven the convention is to have your tests named "GwtTest*" for GWT based unit tests and ending with either "Test" or "TestCase" for plain old Unit Tests. Luckely this is a simple change. I renamed the "BackOfficeTest.java" file to "GwtBackOffice.java" with the following command:<pre>$ git mv src/test/java/org/nuno/backoffice/client/BackOfficeTest.java src/test/java/org/nuno/backoffice/client/GwtTestBackOffice.java</pre>Next I edited the file to change the name of the class. I will try to explain how to have 70% of your unit tests being plain old JUnit tests (without GWT) overhead in a future entry.<br /><br />Since I'm want to use Eclipse's Maven plug-in I simply deleted the eclipse projects with "git rm .classpath .project". Now comes the <i>hard</i> part: the Project Object Model (POM).<br /><br />Making a POM for a GWT project was a collection of trials and errors with many searches on Google, forums and others. I finally got a simple POM that works for all that I needed so far, that is, to build the project, run simple unit tests and GWT based tests, run in development mode, make unit and coverage reports and that can be used directly from Eclipse.<br /><br />The <a href="http://mojo.codehaus.org/gwt-maven-plugin/plugin-info.html">GWT for Maven plug-in</a> has support to generate the ASYNC interfaces automatically. I decided to use this support I went ahead and removed the Async version of the interface as follows:<pre>$ git rm src/main/java/org/nuno/backoffice/client/GreetingServiceAsync.java<br /></pre>With all these steps and a lot of debugging, trial and error I ended up with this POM:<pre style="background:black"><<span style="color: #00ffff;">?</span><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">xml</span> <span style="color: #eedd82;">version</span>=<span style="color: #ffa07a;">"1.0"</span> <span style="color: #eedd82;">encoding</span>=<span style="color: #ffa07a;">"</span><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">UTF</span><span style="color: #ffa07a;">-8"</span>?><br /><<span style="color: #87cefa;">project</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xmlns</span>=<span style="color: #ffa07a;">"http://maven.apache.org/POM/4.0.0"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xmlns</span>:<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xsi</span>=<span style="color: #ffa07a;">"http://www.w3.org/2001/XMLSchema-instance"</span><br /> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xsi</span>:<span style="color: #ff4500; font-weight: bold; text-decoration: underline;">schemaLocation</span>=<span style="color: #ffa07a;">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"</span>><br /> <<span style="color: #87cefa;">modelVersion</span>>4.0.0</<span style="color: #87cefa;">modelVersion</span>><br /> <<span style="color: #87cefa;">groupId</span>>org.nuno.backoffice</<span style="color: #87cefa;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">BackOffice</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> <<span style="color: #87cefa;">version</span>>0.0.1-SNAPSHOT</<span style="color: #87cefa;">version</span>><br /> <<span style="color: #87cefa;">packaging</span>>war</<span style="color: #87cefa;">packaging</span>><br /> <<span style="color: #87cefa;">name</span>>Back Office</<span style="color: #87cefa;">name</span>><br /> <br /> <<span style="color: #87cefa;">properties</span>><br /> <<span style="color: #87cefa;">gwt.version</span>>2.0.3</<span style="color: #87cefa;">gwt.version</span>><br /> </<span style="color: #87cefa;">properties</span>><br /><br /> <<span style="color: #87cefa;">dependencies</span>><br /> <<span style="color: #87cefa;">dependency</span>><br /> <<span style="color: #87cefa;">groupId</span>>com.google.gwt</<span style="color: #87cefa;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span>-<span style="color: #ff4500; font-weight: bold; text-decoration: underline;">servlet</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> <<span style="color: #87cefa;">version</span>>${gwt.version}</<span style="color: #87cefa;">version</span>><br /> <<span style="color: #87cefa;">scope</span>><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">runtime</span></<span style="color: #87cefa;">scope</span>><br /> </<span style="color: #87cefa;">dependency</span>><br /> <<span style="color: #87cefa;">dependency</span>><br /> <<span style="color: #87cefa;">groupId</span>>com.google.gwt</<span style="color: #87cefa;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span>-user</<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> <<span style="color: #87cefa;">version</span>>${gwt.version}</<span style="color: #87cefa;">version</span>><br /> <<span style="color: #87cefa;">scope</span>>provided</<span style="color: #87cefa;">scope</span>><br /> </<span style="color: #87cefa;">dependency</span>><br /><br /> <span style="color: #ff4500;"><!-- </span><span style="color: #ff4500;">Test dependencies </span><span style="color: #ff4500;">--></span><br /> <<span style="color: #87cefa;">dependency</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">groupId</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> <<span style="color: #87cefa;">version</span>>4.7</<span style="color: #87cefa;">version</span>><br /> <<span style="color: #87cefa;">scope</span>>test</<span style="color: #87cefa;">scope</span>><br /> </<span style="color: #87cefa;">dependency</span>><br /> </<span style="color: #87cefa;">dependencies</span>><br /><br /> <<span style="color: #87cefa;">repositories</span>><br /> <<span style="color: #87cefa;">repository</span>><br /> <<span style="color: #87cefa;">id</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span>-maven</<span style="color: #87cefa;">id</span>><br /> <<span style="color: #87cefa;">url</span>>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo/</<span style="color: #87cefa;">url</span>><br /> </<span style="color: #87cefa;">repository</span>><br /> </<span style="color: #87cefa;">repositories</span>><br /> <br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pluginRepositories</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pluginRepository</span>><br /> <<span style="color: #87cefa;">id</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span>-maven</<span style="color: #87cefa;">id</span>><br /> <<span style="color: #87cefa;">url</span>>http://gwt-maven.googlecode.com/svn/trunk/mavenrepo</<span style="color: #87cefa;">url</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pluginRepository</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pluginRepositories</span>><br /><br /> <<span style="color: #87cefa;">build</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugins</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> <<span style="color: #87cefa;">groupId</span>>org.apache.maven.plugins</<span style="color: #87cefa;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>>maven-compiler-<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> <<span style="color: #87cefa;">configuration</span>><br /> <<span style="color: #87cefa;">source</span>>1.6</<span style="color: #87cefa;">source</span>><br /> <<span style="color: #87cefa;">target</span>>1.6</<span style="color: #87cefa;">target</span>><br /> </<span style="color: #87cefa;">configuration</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> <<span style="color: #87cefa;">groupId</span>>org.codehaus.mojo</<span style="color: #87cefa;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span>-maven-<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> <<span style="color: #87cefa;">version</span>>1.2</<span style="color: #87cefa;">version</span>><br /> <<span style="color: #87cefa;">configuration</span>><br /> <<span style="color: #87cefa;">runTarget</span>>org.nuno.backoffice.Backoffice/Backoffice.html</<span style="color: #87cefa;">runTarget</span>><br /> <<span style="color: #87cefa;">hostedWebapp</span>>${project.build.directory}/gwt-run-war</<span style="color: #87cefa;">hostedWebapp</span>><br /> <<span style="color: #87cefa;">tomcat</span>>${project.build.directory}/tomcat</<span style="color: #87cefa;">tomcat</span>><br /> </<span style="color: #87cefa;">configuration</span>><br /> <<span style="color: #87cefa;">executions</span>><br /> <<span style="color: #87cefa;">execution</span>><br /> <<span style="color: #87cefa;">goals</span>><br /> <<span style="color: #87cefa;">goal</span>><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">generateAsync</span></<span style="color: #87cefa;">goal</span>><br /> <<span style="color: #87cefa;">goal</span>>compile</<span style="color: #87cefa;">goal</span>><br /> <<span style="color: #87cefa;">goal</span>>resources</<span style="color: #87cefa;">goal</span>><br /> <<span style="color: #87cefa;">goal</span>>clean</<span style="color: #87cefa;">goal</span>><br /> </<span style="color: #87cefa;">goals</span>><br /> </<span style="color: #87cefa;">execution</span>><br /> <span style="color: #ff4500;"><!-- </span><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">GWT</span><span style="color: #ff4500;"> Test Cases are run in the test phase instead o the </span><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">integation</span><span style="color: #ff4500;">-test phase </span><span style="color: #ff4500;">--></span><br /> <<span style="color: #87cefa;">execution</span>><br /> <<span style="color: #87cefa;">id</span>><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span>-tests</<span style="color: #87cefa;">id</span>><br /> <<span style="color: #87cefa;">phase</span>>test</<span style="color: #87cefa;">phase</span>><br /> <<span style="color: #87cefa;">goals</span>><br /> <<span style="color: #87cefa;">goal</span>>test</<span style="color: #87cefa;">goal</span>><br /> </<span style="color: #87cefa;">goals</span>><br /> </<span style="color: #87cefa;">execution</span>><br /> </<span style="color: #87cefa;">executions</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /><br /> <span style="color: #ff4500;"><!-- </span><span style="color: #ff4500;">Work around the fact that </span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ff4500;">:test creates a tomcat folder </span><span style="color: #ff4500;">--></span><br /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>>maven-clean-<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> <<span style="color: #87cefa;">configuration</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">filesets</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span>><br /> <<span style="color: #87cefa;">directory</span>>tomcat</<span style="color: #87cefa;">directory</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">filesets</span>><br /> </<span style="color: #87cefa;">configuration</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugins</span>><br /> </<span style="color: #87cefa;">build</span>><br /><br /> <<span style="color: #87cefa;">reporting</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugins</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> <<span style="color: #87cefa;">groupId</span>>org.apache.maven.plugins</<span style="color: #87cefa;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>>maven-surefire-report-<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> <<span style="color: #87cefa;">groupId</span>>org.codehaus.mojo</<span style="color: #87cefa;">groupId</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">emma</span>-maven-<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span></<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">artifactId</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugin</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">plugins</span>><br /> </<span style="color: #87cefa;">reporting</span>><br /></<span style="color: #87cefa;">project</span>><br /></pre><br /><br />With this POM we can simple do:<ul> <li> "mvn package" to build the WAR file (running all unit tests); </li> <li> "mvn gwt:run" to run in development mode </li> <li> "mvn clean" to clean all output </li> <li> "mvn site" to generate the site for the project with all the reports.</li> <li> In principle any other Maven task or phase. </li></ul>Using the M2 plugin for eclipse you can simple import the Maven project but you will have to choose "Maven"->"Update project Configuration" once it is imported so it caches the generated sources folder.<br /><br />The project will work well in eclipse but you won't be able to use GWT eclipse integration fully: you can edit all source files with all the assistance but you can't run the code using the GWT plugin for eclipse. What you can do is configure an external maven target of "gwt:run" and work as if nothing had happened.<br /><br />On future entries I have a lot more things to cover like how to run plain old Unit Tests for 70% of your tests (this POM is already prepared for it); Unit Testing with MVP and whatever comes to mind.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-50218802307528174412010-04-13T19:29:00.002+01:002011-10-05T12:59:02.926+01:00GWT Start-up: improving the Ant Build fileGWT Start-up: improving the Ant Build file<br /><br />In the past weeks I've been investigation <a href="http://code.google.com/webtoolkit/">Google's Web Toolkit</a>. I started looking at it because I wanted a good "Web 2.0" application and JSF was cutting it. I tried using JSF and Porlets but Portlets 2.0 isn't ready for prime time yet: the JSF bridges I've tested still don't work, but that is a topic for another post.<br /><br />Today I want to make a fast track introduction to GWT and to summarise some of those issues and how I worked around them. For now I'll start with the basic project setup.<br /><br />GWT has first class support for Apache's <a href="http://ant.apache.org/">Ant</a> but I wanted to use Maven. Why Maven? It simply makes sense to me because of all the Project Management support it has. You can improve Ant with <a href="http://ant.apache.org/ivy/">Ivy</a> but for me it still feels like shell scripting in XML. If I'm going to pay the price for XML than I want something in return.<br /><br />There is an archetype for GWT and Maven but I simply don't like it so I decided to start with GWT's support for Ant and change the project to have Maven. But before going to Maven I also decided to improve the Ant build file the application creator generates.<br /><br /><b>Creating the Skeleton</b><br /><br />GWT has a tool that automatically creates the skeleton for your application. I used that tool because I didn't want to wast time reinventing the wheel. It is rather simple just run the following command in the folder you want your project to live in:<pre><br />$ webAppCreator -junit ~/.m2/repository/junit/junit/4.7/junit-4.7.jar org.nuno.backoffice.BackOffice<br /></pre><br />I'm using <a href="http://www.junit.org/">JUnit</a>'s jar from by Maven repository. I could have omitted that step but I wanted GWT to generate a Test Case for me so I can use it as a starting point later on. You can check if your project works by simply running "ant devmode".<br /><br /><b>Optimising the build file</b><br /><br />The build file generated by GWT has, in my view, a copy/paste and I believe all copy/paste should be eliminated by refactoring. The part I'm talking about is the test part. The build file has support for running tests in development mode and in production mode. Here is what is generated by GWT:<pre style="background:black" ><br /> <<span style="color: #87cefa;">target</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"test.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dev</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">depends</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">javac</span><span style="color: #ffa07a;">.tests"</span> <span style="color: #eedd82;">description</span>=<span style="color: #ffa07a;">"Run development mode tests"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">mkdir</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"reports/</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">htmlunit</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dev</span><span style="color: #ffa07a;">"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span> <span style="color: #eedd82;">fork</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">printsummary</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">haltonfailure</span>=<span style="color: #ffa07a;">"yes"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">jvmarg</span> <span style="color: #eedd82;">line</span>=<span style="color: #ffa07a;">"-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">Xmx</span><span style="color: #ffa07a;">256m"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">standardsMode</span><span style="color: #ffa07a;"> -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">logLevel</span><span style="color: #ffa07a;"> WARN"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"java.awt.headless"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"true"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">src</span><span style="color: #ffa07a;">"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"test"</span> /><br /> <<span style="color: #87cefa;">path</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">refid</span>=<span style="color: #ffa07a;">"project.class.path"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"/home/nsousa/.m2/repository/junit/junit/4.7/junit-4.7.jar"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">todir</span>=<span style="color: #ffa07a;">"reports/</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">htmlunit</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dev</span><span style="color: #ffa07a;">"</span> ><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"test"</span> ><br /> <<span style="color: #87cefa;">include</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"**/*Test.java"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"plain"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xml</span><span style="color: #ffa07a;">"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span>><br /> </<span style="color: #87cefa;">target</span>><br /><br /> <<span style="color: #87cefa;">target</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"test.prod"</span> <span style="color: #eedd82;">depends</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">javac</span><span style="color: #ffa07a;">.tests"</span> <span style="color: #eedd82;">description</span>=<span style="color: #ffa07a;">"Run production mode tests"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">mkdir</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"reports/</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">htmlunit</span><span style="color: #ffa07a;">.prod"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span> <span style="color: #eedd82;">fork</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">printsummary</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">haltonfailure</span>=<span style="color: #ffa07a;">"yes"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">jvmarg</span> <span style="color: #eedd82;">line</span>=<span style="color: #ffa07a;">"-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">Xmx</span><span style="color: #ffa07a;">256m"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"-prod -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">standardsMode</span><span style="color: #ffa07a;"> -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">logLevel</span><span style="color: #ffa07a;"> WARN -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">standardsMode</span><span style="color: #ffa07a;"> -out </span><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">www</span><span style="color: #ffa07a;">-test"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"java.awt.headless"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"true"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">src</span><span style="color: #ffa07a;">"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"test"</span> /><br /> <<span style="color: #87cefa;">path</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">refid</span>=<span style="color: #ffa07a;">"project.class.path"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"/home/nsousa/.m2/repository/junit/junit/4.7/junit-4.7.jar"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">todir</span>=<span style="color: #ffa07a;">"reports/</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">htmlunit</span><span style="color: #ffa07a;">.prod"</span> ><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"test"</span> ><br /> <<span style="color: #87cefa;">include</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"**/*Test.java"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"plain"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xml</span><span style="color: #ffa07a;">"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span>><br /> </<span style="color: #87cefa;">target</span>><br /></pre>These tasks are basically copy/paste of each other and the only change is the output folder for the reports and the GWT parameters. I decided to refactor them to a macro definition to get things a lot simpler a less error prone. <pre style="background:black"><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">macrodef</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">testgwt</span><span style="color: #ffa07a;">"</span>><br /> <<span style="color: #87cefa;">attribute</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">"</span> /><br /> <<span style="color: #87cefa;">attribute</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"destination"</span> /><br /> <<span style="color: #87cefa;">sequential</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">mkdir</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"reports/@{destination}"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span> <span style="color: #eedd82;">fork</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #ff4500; font-weight: bold; text-decoration: underline;">printsummary</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #ff4500; font-weight: bold; text-decoration: underline;">haltonfailure</span>=<span style="color: #ffa07a;">"yes"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">jvmarg</span> <span style="color: #eedd82;">line</span>=<span style="color: #ffa07a;">"-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">Xmx</span><span style="color: #ffa07a;">256m"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"@{</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">}"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"java.awt.headless"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"true"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">src</span><span style="color: #ffa07a;">"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"test"</span> /><br /> <<span style="color: #87cefa;">path</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">refid</span>=<span style="color: #ffa07a;">"project.class.path"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"/home/nsousa/.m2/repository/junit/junit/4.7/junit-4.7.jar"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">todir</span>=<span style="color: #ffa07a;">"reports/@{destination}"</span> ><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"test"</span> ><br /> <<span style="color: #87cefa;">include</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"**/*Test.java"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"plain"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xml</span><span style="color: #ffa07a;">"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span>><br /> </<span style="color: #87cefa;">sequential</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">macrodef</span>><br /> <br /> <<span style="color: #87cefa;">target</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"test.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dev</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">depends</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">javac</span><span style="color: #ffa07a;">.tests"</span> <span style="color: #eedd82;">description</span>=<span style="color: #ffa07a;">"Run development mode tests"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">testgwt</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #eedd82;">-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span>=<span style="color: #ffa07a;">"-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">standardsMode</span><span style="color: #ffa07a;"> -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">logLevel</span><span style="color: #ffa07a;"> WARN"</span> <span style="color: #eedd82;">destination</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">htmlunit</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dev</span><span style="color: #ffa07a;">"</span> /><br /> </<span style="color: #87cefa;">target</span>><br /><br /> <<span style="color: #87cefa;">target</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"test.prod"</span> <span style="color: #eedd82;">depends</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">javac</span><span style="color: #ffa07a;">.tests"</span> <span style="color: #eedd82;">description</span>=<span style="color: #ffa07a;">"Run production mode tests"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">testgwt</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #eedd82;">-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span>=<span style="color: #ffa07a;">"-prod -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">standardsMode</span><span style="color: #ffa07a;"> -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">logLevel</span><span style="color: #ffa07a;"> WARN -</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">standardsMode</span><span style="color: #ffa07a;"> -out </span><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">www</span><span style="color: #ffa07a;">-test"</span> <span style="color: #eedd82;">destination</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">htmlunit</span><span style="color: #ffa07a;">.prod"</span> /><br /> </<span style="color: #87cefa;">target</span>><br /></pre>Now that the build file has been refactored I decided to make an "ant clean" to find out that it doesn't actually clean all the generated output. Time to fix it.<br /><br /><b>Fixing the clean task</b><br /><br />When I asked ant to clean the project I found out that many artifacts were still laying around. How did I found out? Well, I use git and git pointed them out for me. This is not acceptable: running "ant clean" should clean all output. I immediately fixed the issue.<pre style="background:black"><br /> <<span style="color: #87cefa;">target</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"clean"</span> <span style="color: #eedd82;">description</span>=<span style="color: #ffa07a;">"Cleans this project"</span>><br /> <<span style="color: #87cefa;">delete</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"war/WEB-INF/classes"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">failonerror</span>=<span style="color: #ffa07a;">"false"</span> /><br /> <<span style="color: #87cefa;">delete</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"war/</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">backoffice</span><span style="color: #ffa07a;">"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">failonerror</span>=<span style="color: #ffa07a;">"false"</span> /><br /> <<span style="color: #87cefa;">delete</span> <span style="color: #eedd82;">dir</span>=<span style="color: #ffa07a;">".gwt-tmp"</span> <span style="color: #eedd82;">failonerror</span>=<span style="color: #ffa07a;">"false"</span> /><br /> <<span style="color: #87cefa;">delete</span> <span style="color: #eedd82;">dir</span>=<span style="color: #ffa07a;">"tomcat"</span> <span style="color: #eedd82;">failonerror</span>=<span style="color: #ffa07a;">"false"</span> /><br /> <<span style="color: #87cefa;">delete</span> <span style="color: #eedd82;">dir</span>=<span style="color: #ffa07a;">"reports"</span> <span style="color: #eedd82;">failonerror</span>=<span style="color: #ffa07a;">"false"</span> /><br /> <<span style="color: #87cefa;">delete</span> <span style="color: #eedd82;">dir</span>=<span style="color: #ffa07a;">"www-test"</span> <span style="color: #eedd82;">failonerror</span>=<span style="color: #ffa07a;">"false"</span> /><br /> <<span style="color: #87cefa;">delete</span> <span style="color: #eedd82;">file</span>=<span style="color: #ffa07a;">"BackOffice.war"</span> /><br /> <<span style="color: #87cefa;">delete</span>><br /> <<span style="color: #87cefa;">fileset</span> <span style="color: #eedd82;">dir</span>=<span style="color: #ffa07a;">"test"</span> <span style="color: #eedd82;">includes</span>=<span style="color: #ffa07a;">"**/*.class"</span> /><br /> </<span style="color: #87cefa;">delete</span>><br /> </<span style="color: #87cefa;">target</span>><br /></pre>I think that GWT should already add code coverage support to the default build file. I mean, why not put an option there since GWT now support <a href="http://emma.sourceforge.net/">EMMA</a>? Well I did just that.<br /><br /><b>Code Coverage with EMMA</b><br /><br />I want to be able to run the tests with and without code coverage, just to be sure that the code coverage would be interfering with the tests somehow. So this is what I did. First I added a configuration area for emma on the top of the build file, right after the GWT configuration:<pre style="background:black"> <span style="color: #ff4500;"><!-- </span><span style="color: #ff4500;">Configure path to </span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">GWT</span><span style="color: #ff4500;"> </span><span style="color: #ff4500; font-weight: bold; text-decoration: underline;">SDK</span><span style="color: #ff4500;"> </span><span style="color: #ff4500;">--></span><br /> <<span style="color: #87cefa;">property</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sdk</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"/opt/NonCriticalStorage/Software/gwt-2.0.3"</span> /><br /><br /> <span style="color: #ff4500;"><!-- </span><span style="color: #ff4500;">Configure EMMA </span><span style="color: #ff4500;">--></span><br /> <<span style="color: #87cefa;">property</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"emma.dir"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"/home/nsousa/Software/emma/lib"</span> /><br /><br /> <<span style="color: #87cefa;">target</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"emma"</span> <span style="color: #eedd82;">description</span>=<span style="color: #ffa07a;">"turns on EMMA instrumentation/reporting"</span> ><br /> <<span style="color: #87cefa;">property</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"emma.enabled"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"true"</span> /><br /> </<span style="color: #87cefa;">target</span>><br /><br /> <<span style="color: #87cefa;">path</span> <span style="color: #eedd82;">id</span>=<span style="color: #ffa07a;">"emma.lib"</span> ><br /> <<span style="color: #87cefa;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"${emma.dir}/emma.jar"</span> /><br /> <<span style="color: #87cefa;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"${emma.dir}/emma_ant.jar"</span> /><br /> </<span style="color: #87cefa;">path</span>><br /> <br /> <<span style="color: #87cefa;">taskdef</span> <span style="color: #eedd82;">resource</span>=<span style="color: #ffa07a;">"emma_ant.properties"</span> <span style="color: #eedd82;">classpathref</span>=<span style="color: #ffa07a;">"emma.lib"</span> /><br /><br /> <<span style="color: #87cefa;">path</span> <span style="color: #eedd82;">id</span>=<span style="color: #ffa07a;">"project.class.path"</span>><br /> </pre>The basic idea is that if I specify the "emma" task when calling ant than EMMA will be enabled and I'll have code coverage. If I don't specify the "emma" task then I won't have. In order words, running "ant clean emma test" will run tests with code coverage. Running "ant clean test" will run them without code coverage. I then changed the "javac" task to use EMMA if it is active as follows:<pre style="background:black"> <<span style="color: #87cefa;">target</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">javac</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">depends</span>=<span style="color: #ffa07a;">"libs"</span> <span style="color: #eedd82;">description</span>=<span style="color: #ffa07a;">"Compile java source"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">mkdir</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"war/WEB-INF/classes"</span>/><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">javac</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">srcdir</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">src</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">includes</span>=<span style="color: #ffa07a;">"**"</span> <span style="color: #eedd82;">encoding</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">utf</span><span style="color: #ffa07a;">-8"</span><br /> <span style="color: #ff4500; font-weight: bold; text-decoration: underline;">destdir</span>=<span style="color: #ffa07a;">"war/WEB-INF/classes"</span><br /> <span style="color: #eedd82;">source</span>=<span style="color: #ffa07a;">"1.5"</span> <span style="color: #eedd82;">target</span>=<span style="color: #ffa07a;">"1.5"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">nowarn</span>=<span style="color: #ffa07a;">"true"</span><br /> <span style="color: #eedd82;">debug</span>=<span style="color: #ffa07a;">"true"</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">debuglevel</span>=<span style="color: #ffa07a;">"lines,vars,source"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">refid</span>=<span style="color: #ffa07a;">"project.class.path"</span>/><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">javac</span>><br /> <<span style="color: #87cefa;">copy</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">todir</span>=<span style="color: #ffa07a;">"war/WEB-INF/classes"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">src</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">excludes</span>=<span style="color: #ffa07a;">"**/*.java"</span>/><br /> </<span style="color: #87cefa;">copy</span>><br /> <<span style="color: #87cefa;">emma</span> <span style="color: #eedd82;">enabled</span>=<span style="color: #ffa07a;">"${emma.enabled}"</span> ><br /> <<span style="color: #87cefa;">instr</span> <span style="color: #eedd82;">instrpath</span>=<span style="color: #ffa07a;">"war/WEB-INF/classes"</span><br /> <span style="color: #ff4500; font-weight: bold; text-decoration: underline;">metadatafile</span>=<span style="color: #ffa07a;">"reports/coverage/metadata.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">emma</span><span style="color: #ffa07a;">"</span><br /> <span style="color: #eedd82;">merge</span>=<span style="color: #ffa07a;">"true"</span><br /> <span style="color: #eedd82;">mode</span>=<span style="color: #ffa07a;">"overwrite"</span> /><br /> </<span style="color: #87cefa;">emma</span>><br /> </<span style="color: #87cefa;">target</span>><br /></pre>Then I changed the macro definition for the tests to use EMMA if applicable and to generate EMMA's report as follows (I also added a report for junit):<pre style="background:black;"><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">macrodef</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">testgwt</span><span style="color: #ffa07a;">"</span>><br /> <<span style="color: #87cefa;">attribute</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">"</span> /><br /> <<span style="color: #87cefa;">attribute</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"destination"</span> /><br /> <<span style="color: #87cefa;">sequential</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">mkdir</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"reports/@{destination}"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span> <span style="color: #eedd82;">fork</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #ff4500; font-weight: bold; text-decoration: underline;">printsummary</span>=<span style="color: #ffa07a;">"yes"</span> <span style="color: #ff4500; font-weight: bold; text-decoration: underline;">haltonfailure</span>=<span style="color: #ffa07a;">"yes"</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">jvmarg</span> <span style="color: #eedd82;">line</span>=<span style="color: #ffa07a;">"-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">Xmx</span><span style="color: #ffa07a;">256m"</span> /><br /> <<span style="color: #87cefa;">jvmarg</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"-Demma.coverage.out.file=reports/@{destination}/coverage.emma"</span> /><br /> <<span style="color: #87cefa;">jvmarg</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"-Demma.coverage.out.merge=true"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">.</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"@{</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">gwt</span><span style="color: #ffa07a;">-</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">args</span><span style="color: #ffa07a;">}"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">sysproperty</span> <span style="color: #eedd82;">key</span>=<span style="color: #ffa07a;">"java.awt.headless"</span> <span style="color: #eedd82;">value</span>=<span style="color: #ffa07a;">"true"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">src</span><span style="color: #ffa07a;">"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"test"</span> /><br /> <<span style="color: #87cefa;">path</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">refid</span>=<span style="color: #ffa07a;">"project.class.path"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">pathelement</span> <span style="color: #eedd82;">location</span>=<span style="color: #ffa07a;">"/home/nsousa/.m2/repository/junit/junit/4.7/junit-4.7.jar"</span> /><br /> <<span style="color: #87cefa;">path</span> <span style="color: #eedd82;">refid</span>=<span style="color: #ffa07a;">"emma.lib"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">classpath</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">todir</span>=<span style="color: #ffa07a;">"reports/@{destination}"</span> ><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span> <span style="color: #cdad00; font-weight: bold; text-decoration: underline;">dir</span>=<span style="color: #ffa07a;">"test"</span> ><br /> <<span style="color: #87cefa;">include</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"**/*Test.java"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">fileset</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">batchtest</span>><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"plain"</span> /><br /> <<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">formatter</span> <span style="color: #eedd82;">type</span>=<span style="color: #ffa07a;">"</span><span style="color: #cdad00; font-weight: bold; text-decoration: underline;">xml</span><span style="color: #ffa07a;">"</span> /><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">junit</span>><br /> <<span style="color: #87cefa;">junitreport</span> <span style="color: #eedd82;">todir</span>=<span style="color: #ffa07a;">"reports/@{destination}"</span>><br /> <<span style="color: #87cefa;">fileset</span> <span style="color: #eedd82;">dir</span>=<span style="color: #ffa07a;">"reports/@{destination}"</span>><br /> <<span style="color: #87cefa;">include</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"TEST-*.xml"</span> /><br /> </<span style="color: #87cefa;">fileset</span>><br /> <<span style="color: #87cefa;">report</span> <span style="color: #eedd82;">todir</span>=<span style="color: #ffa07a;">"reports/@{destination}"</span> /><br /> </<span style="color: #87cefa;">junitreport</span>><br /> <<span style="color: #87cefa;">emma</span> <span style="color: #eedd82;">enabled</span>=<span style="color: #ffa07a;">"${emma.enabled}"</span> ><br /> <<span style="color: #87cefa;">report</span> <span style="color: #eedd82;">sourcepath</span>=<span style="color: #ffa07a;">"src"</span> ><br /> <<span style="color: #87cefa;">fileset</span> <span style="color: #eedd82;">dir</span>=<span style="color: #ffa07a;">"reports"</span>><br /> <<span style="color: #87cefa;">include</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"coverage/*.emma"</span> /><br /> <<span style="color: #87cefa;">include</span> <span style="color: #eedd82;">name</span>=<span style="color: #ffa07a;">"@{destination}/*.emma"</span> /><br /> </<span style="color: #87cefa;">fileset</span>><br /> <<span style="color: #87cefa;">txt</span> <span style="color: #eedd82;">outfile</span>=<span style="color: #ffa07a;">"reports/@{destination}/coverage.txt"</span> /><br /> <<span style="color: #87cefa;">html</span> <span style="color: #eedd82;">outfile</span>=<span style="color: #ffa07a;">"reports/@{destination}/coverage.html"</span> /><br /> </<span style="color: #87cefa;">report</span>><br /> </<span style="color: #87cefa;">emma</span>><br /> </<span style="color: #87cefa;">sequential</span>><br /> </<span style="color: #cdad00; font-weight: bold; text-decoration: underline;">macrodef</span>><br /></pre>And that is it for getting the Ant build file to a decent state. On the next blog entry I'll talk about making a Maven build file for this project and also on rearranging the project's structure to follow Maven's conventions.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-71096869453147775042010-01-22T15:00:00.002+00:002011-10-05T12:59:11.687+01:00Simplified Option Icon 255 on GentooI have an Option Icon 255 from work to use when I'm out of the office. It is a 3G USB pen. I've used many outside scripts and graphical user interfaces but I never liked them. They crashed a lot and never seemed natural. Also I wanted a script that actually worked all the time instead of failing sometimes because it took the device a couple more seconds to register in the network.<br /><br />My solution: a mix of udev and shell scripts.<br /><br />First I made udev rules for the device. I want it to always have the same name on the /dev file system and that as soon as I connect it to the laptop it should validate the PIN and register in the network.I created a "49-hso.rules" (hso is the name of the kernel driver for the device) in the "/etc/udev/rules.d" folder as follows:<pre>ACTION!="add", GOTO="hso_end"<br /><br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Control", SYMLINK+="wctrl0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Application", SYMLINK+="wapp0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Application", SYMLINK+="wappa0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Application2",SYMLINK+="wappb0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Diagnostic", SYMLINK+="wdiag0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Diagnostic", SYMLINK+="wdiaga0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Diagnostic2", SYMLINK+="wdiagb0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="Modem", SYMLINK+="wmodem0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="GPS", SYMLINK+="wgps0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="GPS_Control", SYMLINK+="wgpsc0"<br />SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTR{hsotype}=="PCSC", SYMLINK+="wpcsc0"<br /><br />KERNEL=="ttyHS[0-9]*", NAME="%k", GROUP="plugdev", MODE="0660"<br /><br />ATTRS{idVendor}=="0af0", ATTRS{idProduct}=="6971", RUN+="/etc/hso/setPin"<br /><br />LABEL="hso_end"</pre>I copied these rules from <a href="http://en.gentoo-wiki.com/wiki/Option_Icon_225"/>here</a>. They should work with other hso devices, but I never tested it.<br /><br />The magic is all in "/etc/hso" (I created this folder to hold all the scripts). First I created the "setPin" script as follows:<pre>#!/bin/bash<br /><br />OUTPUTFILE=/tmp/output.hso-chat<br /><br />( /usr/sbin/chat -E -s -V -f /etc/hso/pin-chat < /dev/wctrl0 > /dev/wctrl0 ) 2> $OUTPUTFILE</pre>I leave the tmp file as I might want to debug it. The "chat-pin" chat script is the following (remember to put your PIN where "PIN-HERE" is written since I removed mine):<pre>ABORT ERROR<br />TIMEOUT 10<br />"" ATZ<br />OK "AT+CPIN=\"PIN-HERE\"^m"<br />OK "\d\d\d\d\d\d\dAT+COPS=?^m"<br />OK "AT+CGDCONT=1,,\"internet\"^m"</pre>Yes, the "^m" are on the spot. You may need to adapt the apn name (mine is internet). If you have a user and password will have to add it to the AT+CGDCONT command. Just check the <a href="http://en.gentoo-wiki.com/wiki/Option_Icon_225">wiki</a> for it. With these steps you should be able to plug the device and notice that it registers with the network. To connect to the network I created a "/etc/hso/connect" script as follows:<pre>#!/bin/bash <br /><br />PIP=""<br />COUNTER=""<br />OUTPUTFILE="/tmp/hso.chat"<br />DEVICE="/dev/wctrl0" <br />NETDEV=hso0 <br /><br />while [ -z "$PIP" -a "$COUNTER" != "------" ]<br />do <br /> echo "trying$COUNTER" <br /> sleep 2 <br /> rm -f $OUTPUTFILE<br /> ( /usr/sbin/chat -E -s -V -f /etc/hso/con-chat <$DEVICE > $DEVICE ) 2> $OUTPUTFILE<br /> ISERROR=`grep '^ERROR' $OUTPUTFILE`<br /> if [ -z "$ISERROR" ]<br /> then<br /> PIP="`grep '^_OWANDATA' $OUTPUTFILE | cut -d, -f2`"<br /> NS1="`grep '^_OWANDATA' $OUTPUTFILE | cut -d, -f4`"<br /> NS2="`grep '^_OWANDATA' $OUTPUTFILE | cut -d, -f5`"<br /> fi<br /><br /> COUNTER="${COUNTER}-"<br /><br />done<br /><br />if [ -z "$PIP" ]<br />then<br /> echo "We did not get an IP address from the provider, bailing ..."<br /> cat $OUTPUTFILE<br /> rm -f $OUTPUTFILE<br /> exit<br />fi<br />rm -f $OUTPUTFILE<br /><br />echo "Setting IP address to $PIP"<br />ifconfig $NETDEV $PIP netmask 255.255.255.255 up<br /><br />echo "Adding route"<br />route add default dev $NETDEV<br /><br />echo "Adding name servers"<br />( echo nameserver $NS1 ; echo nameserver $NS2 ) | resolvconf -a $NETDEV<br /><br />echo "Done!"</pre><br /><br />The "/etc/hso/con-chat" script referenced is as follows:<pre>ABORT ERROR<br />TIMEOUT 10<br />"" ATZ<br />OK "AT_OWANCALL=1,1,0^m"<br />OK "\d\d\d\d\dAT_OWANDATA=1^m"<br />OK ""</pre>And with this it should work. Notice that I'm using openresolv to manage my name servers. If you aren't then you probably are better of changing the "connect" script to copy the previous resolv.conf and replace it with another. I just prefer to have openresolv since it takes care of things such as restarting the nscd (Naming Service Cache Daemon, if you are wondering). My end goal is to use dnsmasq and to route only the DNS requests to the company VPN. For that I'm better off using openresolv.<br /><br />Now that you are connected you need to be able to disconnect :-). The script is very simple:<pre>#!/bin/bash<br /><br />DEVICE="/dev/wctrl0"<br />NETDEV=hso0<br /><br />ifconfig $NETDEV down<br /><br />/usr/sbin/chat -V -f /etc/hso/dis-chat <$DEVICE >$DEVICE 2> /dev/null<br /><br />resolvconf -d $NETDEV</pre>And you also need a chat script in "/etc/hso/dis-chat" as follows:<pre>TIMEOUT 10<br />ABORT ERROR<br />"" ATZ<br />OK "AT_OWANCALL=1,0,0^m"<br />OK ""</pre>And that should do it. At least it works for me :-)Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-16614003423449230152010-01-06T19:08:00.004+00:002011-10-05T12:58:38.380+01:00Gentoo with LUKS and LVMMy company has security policy that forces us to encrypt the hard drive of the computer and any other media. Well, not the whole hard drive, but 99% of it: the 1% is what is required for the PC to boot and ask for a password to decrypt the rest of the drive. The good news is that I'm allowed to use Linux. The bad news is that they have red hat enterprise linux and I like Gentoo. For a long time I've been using kubuntu. It is not bad, but it is too easy to use that it borks some time and I like the control Gentoo gives. Since I only installed Gentoo 2 times, one in 2003 and another in 2007 I decided to write all the steps for a bare minimum Gentoo installation. I have tested these steps on a Virtual Machine using KVM. Next step is to make it on the real laptop. It should take something like 35 minutes to do this on a Core 2 Duo at 2.2ghz.<br />
<br />
<span style="font-weight: bold;">Notice:</span> This works for me. Use it at your own risk and remember that these commands wipe your hard drive so, if you want something special read the commands and adapt.<br />
<br />
The list of steps is optimized. For more information you should read the gentoo handbook.<br />
<br />
<span style="font-weight: bold;">Partition the hard Drive</span><br />
<br />
I used a simple partition scheme: 200mb for the boot (the 1% that is not encyrpted) and the rest for the crypted part. The crypted part is 512mb for the swap and the rest for the root file system. Everything is using ext4.<br />
<br />
Using fdisk delete all the partitions on the harddrive and create two partitions: one with 200Mb (+200M in fdisk) and another with the rest.<br />
<br />
<span style="font-weight: bold;">Crypt and Open the Crypted Parition</span><br />
<br />
Execute the following command:<br />
<pre>cryptsetup -y --cipher serpent-cbc-essiv:sha256 --key-size 256 luksFormat /dev/sda2</pre>
I'm using serpent because it has no patent issues and it is one of the fastest according to a benchmark I saw on the web.<br />
<br />
You will have to answer YES (in upper case) and then enter and verify the pass-phrase. <br />
If for some reason you loose this pass-phrase then you loose your data. You have backups don't you? If not, good luck trying to crack it :-)<br />
<br />
After creating the crypted mapping you need to open it with the command:<br />
<pre>cryptsetup luksOpen /dev/sda2 sda2_crypt</pre>
<span style="font-weight: bold;">LVM Setup</span><br />
<br />
This is quite easy: just do the following (I'm calling internalhd to the volume, but you can choose another name).<br />
<pre>
pvcreate /dev/mapper/sda2_crypt
vgcreate internalhd /dev/mapper/sda2_crypt
lvcreate -L512m -nswap internalhd
lvcreate -L7G -nroot internalhd</pre>
Next step is to create the swap and all the file systems. I chose ext4 and created all file systems and swap with labels. This allows me to use the label in the fstab later.<br />
<pre>
mkswap -L SWAP /dev/mapper/internalhd-swap
swapon /dev/mapper/internalhd-swap
mkfs.ext4 -j /dev/mapper/internalhd-root -L ROOT
mount /dev/mapper/internalhd-root /mnt/gentoo
mkfs.ext4 -j /dev/sda1 -L BOOT
mount /dev/sda1 /mnt/gentoo/boot</pre>
<span style="font-weight: bold;">Gentoo Install</span><br />
<br />
If you need to setup a proxy now is the time ("export http_proxy=..."). Just remember that you need to configure it also in links.<br />
<br />
Use links and download the stage3 tarball and portage snapshot. You can do "links http://www.gentoo.org/main/en/mirrors.xml", choose a mirror and navigate.<br />
<br />
Next you extract all the things:<br />
<pre>
cd /mnt/gentoo
tar xvjpf stage3-*.tar.bz2
tar xvjf /mnt/gentoo/portage-latest.tar.bz2 -C /mnt/gentoo/usr</pre>
Now its time to configure the portage. I opted to do it the easy way. Editing /mnt/gentoo/etc/make.conf and changing CLFAGS to "-O2 -march=native -pipe" and making CXXFLAGS="${CFLAGS}". I also aded MAKEOPTS="-j" and FEATURES="fixpackages sandbox". Later on I added the test features, but for now it is off to avoid a bug in the glib ebuild file. I need to check it and report it back to gentoo.<br />
<br />
Next you need to select a mirror for packages and for rsync. Jut do:<br />
<pre>
mirrorselect -i -o >> /mnt/gentoo/etc/make.conf
mirrorselect -i -r -o >> /mnt/gentoo/etc/make.conf</pre>
Final preparations and entering the gentoo installation using chroot:<br />
<pre>
cp -L /etc/resolv.conf /mnt/gentoo/etc/
mount -t proc none /mnt/gentoo/proc
mount -o bind /dev /mnt/gentoo/dev
chroot /mnt/gentoo /bin/bash
env-update
source /etc/profile
export PS1="(chroot) $PS1"
cp /usr/share/zoneinfo/GMT /etc/localtime</pre>
The last command will change the shell prompt so we remember were we are doing things. Next you can select your profile. I choose the desktop profile:<br />
<pre>
eselect profile list
eselect profile set 2</pre>
You should also choose your locale by editing "/etc/locale.gen". I use 2 locales: en_GB and pt_PT. I do a little trick by doing the following:<br />
<pre>
grep en_GB /usr/share/i18n/SUPPORTED >> /etc/locale.gen
grep pt_PT /usr/share/i18n/SUPPORTED >> /etc/locale.gen</pre>
<br />
<br />
Then you should run "locale-gen" to generate the i18n information for the chosen locales.<br />
<br />
<span style="font-weight: bold;">Configuring the kernel</span><br />
<br />
I'm going to use genkernel because it has support for lvm, luks and so forth. But it has a bug: although it builds lvm internally to use in its initrd image it does not do so for luks. The solution is to emerge cryptsetup before. Well, since I'm emerge the kernel I simply emerge all the packages that I'm going to need later on with the command:<br />
<pre>
emerge -av gentoo-sources genkernel syslog-ng logroate dhcpcd lvm2 cryptsetup grub</pre>
I then add the log daemon to the default run level with:<br />
<pre>
rc-update add syslog-ng default</pre>
You need to tune the "/etc/genkernel.conf" file. Here are the options you should change (the LUKS option must be added since it doesn't exist):<br />
<pre>
CLEAN="no"
MAKEOPTS="-j2"
LVM="yes"
LUKS="yes"
BUSYBOX="yes"
MENUCONFIG="yes"
DISKLABEL="yes"</pre>
I chose no cleaning because I don't want it to clean on each attempt. Then you can issue "genkernel all" and make sure you have the following kernel options (of course you should have the kernel options tuned for your computer):<br />
<pre>
Device Drivers --->
Multi-device support (RAID and LVM) --->
[*] Multiple devices driver support (RAID and LVM)
< > RAID support
<*> Device mapper support
<*> Crypt target support
File systems
<*> The extended 4 (ext3) file system
Cryptographic API
<*> SHA224 and SHA256 digest algorithm
<*> AES cipher algorithms (i586)
<*> Serpent cipher algorithm</pre>
The cryptographic APIs can't be modules. It seems genkernel only includes storage modules in the initrd... I simply tried it and it didn't work and since the disk is always encrypted why have it as modules?<br />
<br />
<span style="font-weight: bold;">Configuring the System</span><br />
<br />
First you need to change "/etc/fstab". You labels as follows:<br />
<pre>
LABEL=BOOT /boot ext4 ...
LABEL=ROOT / ext4 ...
LABEL=SWAP none swap ...</pre>
Set your hostname by editing "etc/hostname"<br />
<br />
Change the root password by running "passwd". You can add a user for yourself now or after you boot.<br />
<br />
Don't forget to set your keymap in "/etc/conf.d/keymaps" and to set your clock settings in "/etc/conf.d/clock".<br />
<br />
<span style="font-weight: bold;">Grub Configuration</span><br />
<br />
Edit grubs configuration file "/boot/grub/grub.conf". Add something like the following (might need to be adapted if the kernel version is different):<br />
<pre>
title Gentoo Linux 2.6.31-r6
root (hd0,0)
kernel /boot/kernel-genkernel-x86-2.6.31-gentoo-r6 root=/dev/ram0 crypt_root=/dev/sda2 real_root=/dev/mapper/internalhd-root dolvm quiet
initrd /boot/initramfs-genkernel-x86-2.6.31-gentoo-r6</pre>
To install grub I do the following (a short cut from the gentoo handbook):<br />
<pre>
grep -v rootfs /proc/mounts > /etc/mtab
grub-install --no-floppy /dev/sda</pre>
<span style="font-weight: bold;">Reboot into it</span><br />
<br />
Now that everything is ready you can reboot into the system. Do the following:<br />
<pre>
exit
cd
umount /mnt/gentoo/boot
umount /mnt/gentoo/dev
umount /mnt/gentoo/proc
umount /mnt/gentoo
reboot</pre>
<span style="font-weight: bold;">Next steps</span><br />
<br />
Since the disk is encrypted and if you forget something in your kernel you won't be able to boot. What I did was to create a backup kernel like this:<br />
<pre>
cp /boot/kernel-genkernel-x86-2.6.31-gentoo-r6 /boot/kernel-backup
cp /boot/initramfs-genkernel-x86-2.6.31-gentoo-r6 /boot/initramfs-backup</pre>
And added its entry to grub:<br />
<pre>
title Gentoo Backup Kernel
root (hd0,0)
kernel /boot/kernel-backup root=/dev/ram0 crypt_root=/dev/sda2 real_root=/dev/mapper/internalhd-root quiet
initrd /boot/initramfs-backup</pre>
<span style="font-weight: bold;">Even more steps</span><br />
<br />
I advise you to emerge some utilities for network and portage as follows:<br />
<pre>
emerge -av mirrorselect openresolv eix portage-utils gentoolkit</pre>
"eix" indexes portage and it is really fast. You should create the index and then do your first sync but using "eix" so it updates the index in the end.<br />
<pre>
eix-update
eix-sync</pre>
Finally some tuning of "/etc/conf.drc" (to get a faster startup and, since this is a laptop, ensure it isn't waiting for eth0 to be available before starting other services):<br />
<pre>
RC_PARALLEL_STARTUP="yes"
RC_NET_STRICT_CHECKING="lo"</pre>
Next you should check if your system is really secure:<br />
<pre>
glsa-check -f all</pre>
And then you can have fun emerging packages, but since you synced recently and probably changed profile you should do something like:<br />
<pre>
emerge -uDNav world</pre>
<span style="font-weight: bold;"><span style="font-style: italic;">Have fun!!!</span></span>Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com2tag:blogger.com,1999:blog-34409529.post-56805821236671978932009-12-15T22:03:00.003+00:002009-12-15T22:14:42.834+00:00Getting NetBeans to do Anti-AliasingI changed desktop environment from KDE to none when Gentoo marked KDE 4 as stable. Don't get me wrong: it has nothing to do with KDE 4 itself. The problem is that my computer is rather old and it was already getting a little slow with KDE 3.5. KDE 4 is heavier and slower bringing me to the tipping point. No, GNOME is not the answer: I switched from GNOME to KDE when GNOME got too bloated and don't get me started with mono...<br /><br />Now I'm using <a href="http://icculus.org/openbox/index.php/Main_Page">openbox</a>, considering <a href="http://wmii.suckless.org/">wmii</a> or <a href="http://www.enlightenment.org/">enlightenment</a> but not a full desktop. I added <a href="http://adesklets.sourceforge.net/">adesklets</a> to the mix, <a href="http://conky.sourceforge.net/">conky</a>, <a href="http://code.google.com/p/tint2/">tint2</a> and <a href="http://phrat.de/yeahtools.html">yeahconsole</a> and I'm ready to work.<br /><br />A couple of days ago a colleague had issues with NetBeans on Gentoo, specifically the fonts had no anti-aliasing, hinting, whatever you want to call it. I tried it today because I was using NetBeans to do some PHP coding. Well, I had the same problem.<br /><br />After some investigation I finally found a way to get it back to work without running KDE or GNOME and I though of sharing it here hopping the next guy can find it easier.<br /><br />According to Sun's JDK documentation you can defined a "_JAVA_OPTIONS" environment variable with the options that the VM should use when starting. You can also force AWT to use a given fixed AA Font Settings and ignore the non existing desktop. In the end you have to make "_JAVA_OPTIONS" have the value "-Dawt.useSystemAAFontSettings=lcd" or any of the values defined in the <a href="http://java.sun.com/javase/6/docs/technotes/guides/2d/flags.html#aaFonts">JDK docs</a>.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com1tag:blogger.com,1999:blog-34409529.post-11770584098743542502009-11-17T22:27:00.004+00:002011-10-05T12:59:22.612+01:00CMake Cross-CompilingI don't know if I already mentioned, but I'm writing and ODBC driver at work. A colleague of mine proposed that the driver is open sourced since it is not our main business. I hope it is, but I'm keeping my hopes high. In the mean time I can share what I have learnt.<br /><br />The driver is an ODBC-RESTful bridge, that is, ODBC requests are <span style="font-style:italic;">transformed</span> into HTTP Restful requests. Although the initial goal of the driver was to be Linux only we had to change it because of the wonderful reporting tool chosen. So I had to <span style="font-style:italic;">port</span> it to Windows. I wont go on the tiny details on how to write portable C code (basically using <span style="font-style:italic;">#ifdefs</span>) but on using CMake and cross-compiling. You see I went and tried to use Microsoft Visual Studio Express, the latest version, but the compiler was so slow, the IDE was, well, horrible and the Operating System is a stone in my shoe, even if executed in a virtual machine. So I decided to put MinGW to a good use and cross compile, that is, to compile on linux a windows executable. Well, in this case a DLL, since ODBC drivers are DLLs.<br /><br />I'm liking CMake more everyday and cross-compilation is one of the things I liked. So, this is how you can do it. The instructions here are really boring because I'm using kubuntu at work. I need to allocate some time to get gentoo into the company's laptop. Gentoo rules in cross-compilation, not to mention a lot more things - I still have a 9 year old lappy with gentoo that I use for my private work. The crazy thing is that I always upgraded it: never reinstalled it. But back to cross-compilation. <br />In kubuntu (and I suppose all debian derivatives) if you want to build a windows executable you have to install mingw32. It is composed of 3 packages: mingw32, mingw32-binutils and mingw32-runtime. This will setup a /usr/i586-mingw32msvc/ folder with all the tools.<br /><br />The solution I found to get CMake to use these tools is to create a toolchain file. This CMake file will contain all the definitions for the new platform. Here is small sample of a <span style="font-style:italic;">Toolchain-windows.cmake</span> file.<br /><pre style="background:black"><font face="monospace"><font color="#ffff00"><b>SET</b></font><font color="#00ffff"><b>(CMAKE_SYSTEM_NAME Windows)</b></font><br /><font color="#ffff00"><b>SET</b></font><font color="#00ffff"><b>(CMAKE_C_COMPILER i586-mingw32msvc-gcc)</b></font><br><br /><font color="#ffff00"><b>SET</b></font><font color="#00ffff"><b>(CMAKE_CXX_COMPILER i586-mingw32msvc-</b></font><font color="#ff40ff"><b>g+</b></font><font color="#00ffff"><b>+)</b></font><br /><br /><font color="#00ffff"><b># Define paths to search for libraries</b></font><br /><font color="#ffff00"><b>SET</b></font><font color="#00ffff"><b>(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc/)</b></font><br /><font color="#ffff00"><b>SET</b></font><font color="#00ffff"><b>(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)</b></font><br /><br /><font color="#00ffff"><b># Don't search in native paths, just the specified root paths</b></font><br /><font color="#ffff00"><b>SET</b></font><font color="#00ffff"><b>(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)</b></font><br /><font color="#ffff00"><b>SET</b></font><font color="#00ffff"><b>(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)</b></font></font></pre>Now to get a windows build what I do is create a folder side by side with the projects folder. For instance, if the project is in the folder A with all the CMake and source files I create a A-Windows, go into it and run:<br /><pre style="background:black; color:white;"><font face="monospace">cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-windows.cmake ..<br />make</font></pre>And I get my windows version of the software. Of course you will have to <span style="font-style:italic;">port</span> your code to windows. Remeber the <span style="font-style:italic;">#ifdef WIN32</span> and, if you need to add more libraries to your executable do something like this on the <span style="font-style:italic;">CMakeLists.txt</span> file:<br /><pre style="background:black"><font color="#ffff00"><b>if</b></font><font color="#00ffff"><b> ( </b></font><font color="#ff40ff"><b>"</b></font><font color="#00ff00"><b>${CMAKE_SYSTEM_NAME}</b></font><font color="#ff40ff"><b>"</b></font><font color="#00ffff"><b> </b></font><font color="#ffff00"><b>MATCHES</b></font><font color="#00ffff"><b> </b></font><font color="#ff40ff"><b>"Windows"</b></font><font color="#00ffff"><b> )</b></font><br /> <font color="#ffff00"><b>set</b></font><font color="#00ffff"><b> (LIBS </b></font><font color="#00ff00"><b>${LIBS}</b></font><font color="#00ffff"><b>wsock32)</b></font><br /><font color="#ffff00"><b>endif</b></font><font color="#00ffff"><b> ( </b></font><font color="#ff40ff"><b>"</b></font><font color="#00ff00"><b>${CMAKE_SYSTEM_NAME}</b></font><font color="#ff40ff"><b>"</b></font><font color="#00ffff"><b> </b></font><font color="#ffff00"><b>MATCHES</b></font><font color="#00ffff"><b> </b></font><font color="#ff40ff"><b>"Windows"</b></font><font color="#00ffff"><b> )</b></font></pre>And <span style="font-weight:bold;">try</span> to have fun. At least you can do most of your development on a decent platform with decent tools.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-5225495985928052202009-10-13T20:40:00.004+01:002009-10-13T21:50:31.177+01:00Back to C: CMake and CUnitI'm back at programming in C. I proposed something 8 months ago at work that was totally ignore. Now my boss wants me to do it because the other alternatives have totally failed. The idea is to implement an ODBC Driver. If I have the time I'll put a tutorial here on how to do that on Linux. But back to the point of this entry.<br /><br />This small guide will help you create a simple project using <a href="http://www.cmake.org/">CMake</a> to build it and <a href="http://cunit.sourceforge.net/">cunit</a> to test it. Yes, I believe in test driven development, no matter the language.<br /><br />Let's imagine a simple project that produces an executable that prints the result of 2 + 3 (I know, lame but sufficient for this example). To make it easier to test I split the application. The functions will go into a library and there will be a source file that starts the program. The library header file is called "lib.h" (extra points for originality). Here are its contents:<pre width="80"><strong><font color="#4169E1">int add(int a, int b)</font></strong>;</pre> <br />The implementation is on the lib.c file as follows:<br /><pre width="80"><strong><font color="#4169E1"><a name="add"></a>int add(int a, int b)</font></strong> {<br /> <font color="#4169E1">return</font> a + b;<br />}</pre> <br />As you can see it is a <i>very</i> complicated function. The adder.c file contain the main function and starts the program as follows:<br /><pre width="80"><font color="#A020F0">#include <stdio.h></font> <br /><font color="#A020F0">#include </font><font color="#666666">"lib.h"</font><font color="#A020F0"></font> <br /> <br /><strong><font color="#4169E1"><a name="main"></a>int main (int argc, char** argv)</font></strong> {<br /> printf(<font color="#666666">"2+3=%d\n"</font>, add(2, 3));<br /> <font color="#4169E1">return</font> 0;<br />}<br /></pre><br />The unit test is a little more complicated as cunit requires some boiler plate code in order to run tests. Here is the source code of the test_lib.c file:<br /><pre width="80"><font color="#A020F0">#include </font><font color="#666666">"CUnit/Basic.h"</font><font color="#A020F0"></font> <br /><font color="#A020F0">#include </font><font color="#666666">"lib.h"</font><font color="#A020F0"></font><br /> <br /><strong><font color="#4169E1"><a name="simpleTest"></a>void simpleTest(void)</font></strong> {<br /> CU_ASSERT(2 == add(1, 1));<br />}<br /> <br /><strong><font color="#4169E1"><a name="main"></a>int main (int argc, char** argv)</font></strong> {<br /> <br /> CU_pSuite pSuite = NULL;<br /> <br /> <font color="#B22222">/* initialize the CUnit test registry */</font> <br /> <font color="#4169E1">if</font> (CUE_SUCCESS != CU_initialize_registry())<br /> <font color="#4169E1">return</font> CU_get_error();<br /> <br /> <font color="#B22222">/* add a suite to the registry */</font> <br /> pSuite = CU_add_suite(<font color="#666666">"Suite_1"</font>, NULL, NULL);<br /> <font color="#4169E1">if</font> (NULL == pSuite) {<br /> CU_cleanup_registry();<br /> <font color="#4169E1">return</font> CU_get_error();<br /> }<br /> <br /> <font color="#B22222">/* add the tests to the suite */</font> <br /> <font color="#4169E1">if</font> (NULL == CU_add_test(pSuite, <font color="#666666">"Simple Addition Test"</font>, simpleTest)) {<br /> CU_cleanup_registry();<br /> <font color="#4169E1">return</font> CU_get_error();<br /> }<br /> <br /> <font color="#B22222">/* Run all tests using the CUnit Basic interface */</font> <br /> CU_basic_set_mode(CU_BRM_VERBOSE);<br /> CU_basic_run_tests();<br /> CU_cleanup_registry();<br /> <font color="#4169E1">return</font> CU_get_error();<br />}</pre><br />To make all this build with CMake you have to create a CMakeLists.txt file with the following content:<br /><pre style="background:black"><font face="monospace"><font color="#ffff00"><b>cmake_minimum_required</b></font><font color="#00ffff"><b> (VERSION 2.6)</b></font><br /><font color="#ffff00"><b>project</b></font><font color="#00ffff"><b> (Adder)</b></font><br /><br /><font color="#ffff00"><b>set</b></font><font color="#00ffff"><b> (SOURCES lib.c)</b></font><br /><br /><font color="#ffff00"><b>add_executable</b></font><font color="#00ffff"><b> (adder adder.c </b></font><font color="#00ff00"><b>${SOURCES}</b></font><font color="#00ffff"><b>)</b></font><br /><br /><font color="#ffff00"><b>enable_testing</b></font><font color="#00ffff"><b> ()</b></font><br /><br /><font color="#ffff00"><b>add_executable</b></font><font color="#00ffff"><b> (test_lib test_lib.c </b></font><font color="#00ff00"><b>${SOURCES}</b></font><font color="#00ffff"><b>)</b></font><br><br /><font color="#ffff00"><b>set_target_properties</b></font><font color="#00ffff"><b> (test_lib PROPERTIES LINK_FLAGS -Wl,-lcunit)</b></font><br><br /><font color="#ffff00"><b>add_test</b></font><font color="#00ffff"><b> (test_lib </b></font><font color="#00ff00"><b>${EXECUTABLE_OUTPUT_PATH}</b></font><font color="#00ffff"><b>/test_lib)</b></font></font></pre><br /><br />And that is it. Now you can make a directory called "build", go into to it and type "cmake .." to generate all the necessary build files. To build the project you type "make", to run the tests you can type "make test" and to clean the output you can run "make clean". If you prefer to do it all in one pass just do "make clean all test".<br /><br />Just in case you are wondering: I used c2html to generate the html formated version of the C files and VIMs convert-to-html script for the CMake file.<br /><br />Happy coding!!!Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com5tag:blogger.com,1999:blog-34409529.post-85428046825659889812009-09-29T21:28:00.002+01:002009-09-29T21:34:17.251+01:00LOL - "Server Too Busy"This just happened to me today. What is more interesting is that this is an unhandled exception. So, the server being to busy is not something that they should predict and allow the application to handle, they just make you wait and then throw this at you. Don't you just love these products.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-aL4HBQRyZWZ16H7UnU2QBNhW5LDOyhMtWYqXzIK5JTXM1Ize2hRXKAsxiYCuuZQLIao6pnMbDH5UlehLGyAeUrwbi31rQnE4UudyTiXtct7Wfdjbu0_QJPverMlK7k7gqn8AXA/s1600-h/ServerTooBusy.jpeg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 192px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-aL4HBQRyZWZ16H7UnU2QBNhW5LDOyhMtWYqXzIK5JTXM1Ize2hRXKAsxiYCuuZQLIao6pnMbDH5UlehLGyAeUrwbi31rQnE4UudyTiXtct7Wfdjbu0_QJPverMlK7k7gqn8AXA/s400/ServerTooBusy.jpeg" border="0" alt=""id="BLOGGER_PHOTO_ID_5386989929926897474" /></a>Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-45231745587245031762009-08-19T22:38:00.002+01:002009-08-19T22:42:00.371+01:00The PlanIt has been some time since I last posted here but I cam across this gem that I had to share. The tile is "<span style="font-weight:bold;">The Plan</span>":<br /><br /><blockquote><br />In the beginning was The Plan.<br />And then came The Assumptions.<br />And The Assumptions were without form.<br />And The Plan was without substance.<br />And a terrible darkness fell upon the face of the Workers. And they<br />spoke among themselves, saying "It is a crock of shit, and it stinks."<br />And the Workers went unto their Supervisors and said loudly "It is a<br />bucket of dung, and we cannot live with the smell."<br />Whereupon the Supervisors went unto their Managers and didst say "It is<br />a container of excrement, and it is very strong, such that none may<br />abide by it." <br />The Managers went quickly up into the temple and seeing there the<br />Directors of the company, went unto them, saying in pious voices "It is<br />a vessel of fertiliser, and none may abide its strength."<br />After much feasting and lewd revellry, the Directors spoke among<br />themselves, saying to one and other "It contains that which aids plant<br />growth, and it is very strong."<br />And together the Directors went up onto the mount and finding there the<br />Vice President, said gravely "It promotes growth, and it is very<br />powerful."<br />Seizing upon this information the Vice President, went unto the<br />President, saying, "This new Plan will actively promote the growth and<br />vigour of the company with very powerful effects."<br />The President looked upon The Plan and saw that it was good.<br />And The Plan became Policy.<br />And this is how Shit Happens.<br /><br />Company Confidential<br /></blockquote>Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-20830671011988721432009-01-08T21:59:00.002+00:002009-01-08T22:07:03.354+00:00Helping out OpenStreeMapIt has been a while since I have last posted but I hope to do it more often. Don't ask me why. I guess that if you are in the bottom you loose all will to do anything. But a two weeks vacation and a few changes in both my personal and professional life and I'm starting to see the light at the end of tunnel.<br />But that is enough drama, on to the goal of this entry.<br />I made my very first contribution to the <a href="http://www.openstreetmap.org/">OpenStreetMap</a>. Think of it like a Wiki that is a map of the whole world. Since my country doesn't have a nice coverage I decided to hack my GPS to track my trips and share them. Then I edited my first roads (two fully and a part of one) and they are already appearing on the site. Next step is to add more roads.<br />Want to help out? You don't even have to edit the roads. Just <a href="http://wiki.openstreetmap.org/wiki/Beginners%27_Guide">trace your trips and upload them</a> they will help others since the more information the more accurate the map will be.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com2tag:blogger.com,1999:blog-34409529.post-17854642965426721132008-10-16T19:56:00.001+01:002008-10-16T19:58:40.005+01:00A Small SurgeryThere are moments in your life when your health throws a curve ball at you. It happened to me several years ago and the end result is now <span style="font-style: italic;">on display</span>.<br /><br />I'm at home, recovering from a surgery. I've been at home for almost 4 weeks and I still have at least 2 more to go before I'm considered able to go to back to work.<br /><br />Although the surgery was nothing too complicated this is my second day almost completely out of bed. I'm now able to sit for small burst of time. For the rest of the time I either stand up and walk or I simply go back to bed.<br /><br />I'm lucky. The day after my surgery, the doctor talked to me. I said it clearly: "Only 50 to 60% of these cases don't recover like we would like them to. When they don't recover in the 2 to 3 weeks like we like them to, then the scale is in the order of months. Minimum 2 to 3 months." That scared my, but I was confident because the doctor said that "90% of the success depends on the patient. If you stick to a few simples rules all should go well." Even with such a bad numbers I decided I could do it, but then I met the nurse.<br /><br />I was released from the hospital the day after I was admitted, 20 hours after I had my surgery. Two days later the nurse came to my parents house to check on me and make the necessary treatments. What she told me left me baffled. She said that 90% of the cases where the doctors chose the approach that was applied on me didn't succeed. That "people simple don't recover as<br />they should e 2 to 3 weeks and then is more like 4 to 6 months". After talking a bit more she finally said she had "never saw a case where it went well." This was mind blowing, but still it didn't made me give up just yet.<br /><br />I new the changes were slim to none, but I had one advantage: my motivation, I simply just wanted to go back to sports as soon as possible, and my diet.<br /><br />One advantage of having gone through a diet and being dead close to the ideal weight for my height is that I don't have as many fat matter as I used to have in the region of the surgery. In fact, I have almost no fat matter in that area, just muscles. This meant that the stitches applied had a better chance of keeping together then all the people that have a lot of fat in that area.<br /><br />The end result is that after 12 days they removed all the stitches, and 23 days after the surgery I was finally able to sitting down at my computer and type a few lines of source code. I still have a couple of weeks to go before I'm able to go to work. My doctor says, and with a good point, that it makes no sense for me to go to work if I can't sit for long periods in front of the computer.<br /><br />If there is a lesson to be learnt from all this, assuming that things won't go terribly wrong in the mean time, is that you should do what the doctor says and no matter the odds you should always focus on your goal and simply believe that you will achieve it no matter the odds.Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-48256156279663828562008-08-22T15:26:00.002+01:002008-08-22T15:32:24.846+01:00A DietI always intended to write about this subject a while back but never got the change to actually sit and write about it. I think this is the time, so if you're looking for a technical or management related blog entry simply skip this one.<br /><br /> Eight months ago I started a diet. I was a "little" overweight and always postponing the task of getting back into shape. I was unable to postpone this any time longer because of my mother.<br /><br /> Some times in your life you need a little push in the right direction. This push can come from many sides. It can be an event that occurred to you. It can simply be a loved one or a friend that has a talk with you. In my case it was my mother actually scheduling an appointment with a nutritionist.<br /><br /> My excuse for not caring about my weight was always that I would first go to a doctor, a nutritionist, before embarking on a diet. Well, my mother took the next step and actually scheduled the appointment and the necessary blood analysis that I had to carry out before the appointment.<br /><br /> I was scared. Not about the appointment but with the results of the analyses. There were some really bad values: that was the last push I needed to start thinking about my health a little more.<br /><br /> What is the end result? Well, I lost a third of my weight. I'm currently in my ideal body weight and feel a lot better. A side effect is that I'm also in a greater shape. I took an ancient old promise I made myself that if I would ever to loose any weight I would also get into shape. Nowadays I run, at least, 30km per week.<br /><br /> I was able not only to loose the extra "baggage" but I was also able to keep my ideal weight for 2 consecutive months. I actually had to cut down on the exercise because I was continuing to loose weight, but this way I get more time to blog.<br /><br /> If you read this far and you want to know the little details about the diet then I'm Sorry. I won't give them to you. My advice: see a doctor and respect what he/she tells you. Don't go for one of those "crazy" diets. What I can leave you with is a before and after picture of yours truly. The first picture is the picture I used to have in the right side of the blog. The second is the new "thin" me that is currently shown in the blog.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikhg8ldblj55nTq6TlKesKslRNqHMz-KT7Ao3qgIuW05Y5pUsWP0SwTR5R8vjfqG74HegeXhTFo2-0lSWCFRrM4_xjNGofF0JnUn35CG67Dbpk7u_oFTMvE9MWoERKO68g_qfgwg/s1600-h/Chat.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikhg8ldblj55nTq6TlKesKslRNqHMz-KT7Ao3qgIuW05Y5pUsWP0SwTR5R8vjfqG74HegeXhTFo2-0lSWCFRrM4_xjNGofF0JnUn35CG67Dbpk7u_oFTMvE9MWoERKO68g_qfgwg/s400/Chat.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5237348878491987938" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYuvKiN0QY_Iv1MqBqeA7NrzJLu_e8hLhG4odIPbhF8Nm69lRg17xRU1F8XsPVfqoeMwbEF13vzKLM_SRCRQYJmccSLtzCiP8tHAdKOpjWPNKlp0RedX3EHpgVon4nsvAhhyphenhyphenqUdw/s1600-h/ChapIMG.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYuvKiN0QY_Iv1MqBqeA7NrzJLu_e8hLhG4odIPbhF8Nm69lRg17xRU1F8XsPVfqoeMwbEF13vzKLM_SRCRQYJmccSLtzCiP8tHAdKOpjWPNKlp0RedX3EHpgVon4nsvAhhyphenhyphenqUdw/s400/ChapIMG.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5237348884241555298" /></a>Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-46930471803496092422008-06-22T14:39:00.003+01:002008-07-12T15:39:36.602+01:00"Moving Out"<div xmlns='http://www.w3.org/1999/xhtml'>It has been a while since I posted anything on the blog. I've been keeping the shared items going because they are part of my daily reads, but nothing regarding the blog itself.<br/><br/>There are many reasons for this but on of them is that I have "moved out" of my parents house. I say "moved out" between quotes because I always go to my parents house on the weekends, but during the week I'm alone on a rented apartment.<br/><br/>Why rent an apartment? Because I was tired of not having any time for myself. With the relocation of my workplace I ended up doing 1 hour drives each way to go to work. This meant 10 hours each week. This had a penalty in my life, not only on my health. My day was fully filled without any time to just breath. Now I live a 10 minute walk from my work. Sufficiently far to refuse to go their if they call me, but close enough to walk and leave the car parked all week long... except when I go windsurfing...<br/><br/>The end result of all this is that I expect to post more frequently and on more technical subjects. Although I expect this I won't make any promises: I'm really enjoying windsurfing and I would trade 2 hours in front of a computer for 1 hour windsurfing...<br/></div>Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0tag:blogger.com,1999:blog-34409529.post-61003683753998954742008-04-19T21:14:00.003+01:002008-04-22T22:27:43.370+01:00So much to do and so little time...It is true: life can throw you a curve when you least expect it.<br /><br />I have some many reasons to blog about but I haven't found the time to get down and actually write anything. What has happened in my left? A lot... Lets see if I can make a short list of the most important things: I lost over 20Kg of weight (and got back up to shape by actually running over 6km every day); I've made a web site for my family's company (that is online and working without a hitch for a couple of weeks now); I've managed to get Gentoo running on an External USB hard drive so I can use the dead weight computer that the company I work for assigned to me while traveling to work on my things (yes, because that thing must have M$ Win...); I've been promoted; I've shown the guys in my company that simply saying it is impossible and giving up is not the answer; and a lot more...<br /><br />Should I talk about it all??? Well, the Linux part I'll leave for another entry because I want to put up the instructions on how you can get a computer running Gentoo, or any Linux flavor for that matter, out of an external USB hard drive. This way you can escape the company man in your off hours...<br /><br />As for the weight loss... I've always said that I would do a diet when I consulted a Nutritionist. Well, my mother went <span style="font-style:italic;">behind my back</span> and scheduled an appointment with one. Well, I was literally out of excuses and went to the doctor in good time: my cholesterol was in a bad level; I was overweighted; I didn't have any energy or endurance. I thought it would be difficult, but with some discipline when eating and a lot of exercise I managed to loose a lot of weight. The main problem is that I had and I'm still wasting money renovating my closet... As for the energy and stamina department? Well, 6.5km a day of running should say everything, but I can add that even after running those kms I'm back to normal e just 15min.<br /><br />On my family's company website: this is a project that I'm doing in part time or my free time, call it what you want. My uncle asked for my opinion on a budget he got from one of those web site building companies. The price tag was shocking, at least for me. It had many defects, it didn't fulfill their use cases and was really expensive. I actually considered opening my own company to make websites. In fact, I'm still considering it.<br /><br />Making the website was fun. It is using all open source technologies, some of which I've used more then 8 years ago. It was interesting to see how far they have become. It was also fun to see if I could make it so intuitive that I wouldn't get bothered with problems with the site. Well, I guess I succeeded because the site hasn't problems, they just want more functionalities :-)<br /><br />As for the company I work for: well, they are going down so fast that it scares me. They want to reduce OPEX (Operational Expenses, for those of you who never heard about it) but they don't even know how to compute it. They want to make tons of money but their first reaction to a client request is: "This is impossible! Let's no answer to the client and maybe it will go away." Come on people, lets get real: if you think it is impossible at least explain it to the customer. You may be surprised by the customer's knowledge and learn something while verifying that it is possible. Not to mention that you don't know squat on the subject you should first ask your colleagues within the company, just in case one of them knows a solution.<br /><br />Facts are that I ended up having to travel to the customer and presenting my solution. Its a simple solution that I think the customer bought. At least they are preparing a business case to get things started. It seems that everything now is business case oriented... I always though we should be user/customer oriented, but who am I to think these things?<br /><br />So, when I get some time I'll post a small guide on getting Gentoo running on an External USB drive and probably some other gems about: Web Services in Java, MySQL and Full Text Search, etc...Nuno Sousahttp://www.blogger.com/profile/12985958024778979830noreply@blogger.com0