woensdag 24 november 2010

Dynamically adding group membership in Linux

This is something I should have known years ago, but I didn't. So, here goes for those that don't know either and happen to stumble on my blog.

When installing some new software that only some users should have access to, a new group is created. The administrator then adds the user name of the users that are allowed to use the software to the entry for the group in /etc/groups.

If a user wants to use the new software immediately that won't work unfortunately. He has to log off and then on again before the system becomes aware of his new group membership.

For a console application however, there is a easy fix. Suppose you just installed rvm and created the new group rvm, let the user issue newgrp rvm and pronto: he will be able to use commands that rely on him being a member of rvm right away.

There are some side effects however. Not only will this group be added to the user's group set, it will become his primary group. Meaning a.o. that, by default, created files will receive the selected group as group id. If you want to avoid that, a user called `johndoe' should issue newgrp johndoe before invoking other commands. This will relegate rvm to secondary group again.

zondag 31 oktober 2010

Getting to know Gradle

Last week I was fed up enough with ant's XML configuration that I started converting my latest project to gradle. I really didn't fancy setting up checkstyle and cobertura for a multi-project build.

It required some getting used to, but after a few days of fighting gradle and groovy (never really used for more a few one-liners) I'm starting to feel comfortable with it. Definitely better than plain old ant.

Gradle brings some of the convention-over-configuration idea of maven, but without feeling as much boxed in. At version 0.9, it's clearly not as evolved as ant or maven, but the clean integration with ant makes up for a great deal.

For Java builds there's the aptly named 'java' plugin. For applying checkstyle I'm using the 'code-quality' plugin. There's no code coverage plugin yet, but the cookbook has a nice section about integrating cobertura. Unfortunately, this is not really targeted at multi-project builds and it uses some hard-coded paths. Also, it completely replaces the plain unit test task with a cobertura-instrumented one, while I would like a non-instrumented version for quick verification from the command line and a fully coverage calculating build for my Hudson CI environment.

To fix these small annoyances, I came up with the following:

  1. add a task called coverage at the main project level that toggles a boolean variable.

    project.computeCoverage = false
    
    task coverage(dependsOn: setupCobertura) << {
      project.computeCoverage = true
    }
    
    The idea is that gradle coverage test does collect coverage information while gradle test does not. At the same time it makes sure the cobertura ant targets are installed, but that's more or less as presented in the cookbook.
  2. Inject tasks into the sub project builds to actually calculate the coverage:

    subprojects {
      // other stuff...
    
      def instrumentationDir = sourceSets.main.classesDir
      def uninstrumentedDir = "${sourceSets.main.classesDir}-orig"
      def cobSerFile = "${project.buildDir}/cobertura.ser"
    
      test.doFirst {
        if ( project.computeCoverage ) {
          ant.taskdef(resource:'tasks.properties', 
                      classpath: configurations.testRuntime.asPath)
          ant {
            delete(file:cobSerFile, failonerror:false)
            delete(dir: uninstrumentedDir, failonerror:false)
            copy(toDir: uninstrumentedDir) { 
              fileset(dir: instrumentationDir) 
            }
            'cobertura-instrument'(datafile:cobSerFile) {
              fileset(dir: instrumentationDir, includes:"**/*.class")
            }
          }
        }
      }
    
      test {
        ignoreFailures = true
        systemProperties ["net.sourceforge.cobertura.datafile"] = cobSerFile
      }
    
      test.doLast {
        if ( project.computeCoverage && 
             new File(uninstrumentedDir).exists() && 
             new File(cobSerFile).exists()) {
          def outputDir = "${project.buildDirName}/${coverageDir}"
          ant {
            delete(file: instrumentationDir)
            move(file: uninstrumentedDir, tofile: instrumentationDir)
            ['xml', 'html'].each {repFormat ->
             'cobertura-report'(destdir: outputDir, 
                                format: repFormat, 
                                datafile: cobSerFile) { 
                sourceSets.main.allJava.addToAntBuilder(ant, 'fileset')
              }
            }
          }
        }
      }
    
    }
    

    The most notable changes from the cookbook are testing the value of the computeCoverage property so that cobertura is only executed when the coverage task is executed first. Also, more than one report format is generated without code duplication and the source sets convention objects are used instead of hard-coded paths.
  3. For making a complete overview of the coverage over all sub projects, I added yet another task:

    task assembleCoverage(dependsOn: coverage) << {
      def dataFile = "${project.buildDirName}/cobertura.ser"
      def destDir = "${project.buildDirName}/${coverageDir}"
      ant {
        delete(file: dataFile, failonerror: false)
        'cobertura-merge'(datafile: dataFile) {
          fileset(dir: '.', includes: "**/cobertura.ser")
        }
        ['xml', 'html'].each {repFormat ->
          'cobertura-report'(destdir: destDir, 
                             format: repFormat, 
                             datafile: dataFile) {
            subprojects.each { subproject -> 
              subproject.sourceSets.main.allJava.addToAntBuilder(ant, 'fileset') }
          }
        }
      }
    }
    
A few issues are still nagging me:
  • I have to define variables outside the ant builder closure because I don't know how to access project properties from within.
  • I'm doing a taskdef in every sub build because they don't appear to be inherited. This is probably fundamental to the working of gradle, but I can't find an explanation in the otherwise extensive manual.
  • I should only generate the XML reports for Hudson and HTML for the local development environment. That's easy enough, but I feel that I have done enough already for a Sunday.
The complete file can be downloaded from my github repository.

If you have any improvement suggestions, by all means use the comments section below.

zaterdag 18 september 2010

Using an event bus to coordinate actions in an MVP-using application

Today I released the source code for my implementation of an event bus. The idea is to use it in web applications built with Vaadin.

Have a look at the github project page. The README there explains the basic usage.

Currently there is support for
  • Sending one event to multiple presenters
  • Just-in-time instantiation and binding of Presenters and Views
  • Splitting an event bus in segments in order to keep related presenters and event together while still being able to send events to the global application

dinsdag 27 juli 2010

ICTects new website launched

It's already a month ago, but after many months saying to myself that I really needed a new site for my company, I finally got a around to creating a new design and content. Since my design skills aren't all that great, my brother was kind enough to give my design a serious overhaul and the result can be admired at http://www.ictects.com/.

For those interested in the technical details: the site is a small sinatra app hosted on heroku. The HTML is generated with haml backed by blueprint.css. As always, the deployment on heroku was a dream. Without any advance planning, it took less than 10 minutes to have the site up and running.