Executing remote shell command via ssh

Yes, you can do:

ssh [user]@[host] [command]

but this works in cases where the first form may not:

echo [command] | ssh [user]@[host] /bin/bash --login -s

It executes the command in exactly the same environment as you’d have logged in via ssh. Trade secret of the ops guru at my work. I was using the first form to execute a server shell script that calls java, and it complained about java command not found. Turns out that the default PATH does not include the JDK bin directory. The second form applies the user profile which sets up the correct PATH.

Using JRebel with a SBT project

I had been wanting to try JRebel for a long time. Today I was reminded of ZeroTurnaound’s offer of a free one year license for Scala developement. Perfect.

Installation is straight-forward. I also created an environment variable called JREBEL_HOME to point to the installation directory. My guinea pig project is a multi-module sbt project. One of the sub project is a standalone app (actually a web app using an embedded jetty). It is configured to run in a forked JVM when launched using sbt’s run command.

First thing first, I enabled JRebel for sbt by adding the following java option in the sbt start script:

-javaagent:$JREBEL_HOME/jrebel.jar

Doing this allows JRebel to reload classes in sbt’s JVM. This is particularly helpful when it comes to working with the embedded Scala REPL (started by sbt’s console command). Without JRebel, everytime I change a class, I have to restart the REPL to load the change. With JRebel, I can test my change without leaving the REPL. That is a huge time-saver and makes REPL a much more useful tool.

That, however, won’t work for the standalone app because it runs in a forked JVM, so I have to modify its javaOptions in the build settings:

...
fork in (Compile,run) := true,
javaOptions in (Compile,run) ++= (System.getenv("JREBEL_HOME") match {
  case null => Seq("-Xmx2G")
  case v    => Seq("-Xmx2G", "-javaagent:" + v + "/jrebel.jar")
}),
...

which adds the JRebel option only if JREBEL_HOME is defined. This way the build works with or without JRebel.

Scala Enumeration pattern matching puzzler

I ran into this issue involving pattern matching Enumerations. It was quite puzzling at first and took me a few minutes to realize what went wrong. To demonstrate, let’s consider an example of building a generic set operation that can handle intersection and complement (i.e. subtraction): an Enumeration is defined to represent the set operator, and a function computes the result given an operator and a sequence of sets as input.

Here is the SetOp enum:

object SetOp extends Enumeration {
  type SetOp = Value
  val intersect, complement = Value
}

The function requires exactly two sets for complement and two or more sets for intersection:

import SetOp._

def doSetOp(op: SetOp, sets: Seq[Set[Int]]) = (op, sets) match {
  case (intersect, s) if s.size > 1 => s.reduce((s1, s2) => s1.intersect(s2))
  case (complement, Seq(s1, s2)) => s1.filterNot(s2.contains)
  case _ => throw new IllegalArgumentException("bad args")
}

To test it:

import SetOp._
val set1 = Set(1, 2, 3)
val set2 = Set(2, 3, 4, 5)
println(doSetOp(intersect, Seq(set1, set2)))
println(doSetOp(complement, Seq(set1, set2)))

One would expect the follwoing output:

Set(2, 3)
Set(1)

However, try it in Scala REPL, and you will get this:

Set(2, 3)
Set(2, 3)

It’s as if complement was matched to intersect! … and indeed it was, but why?? Play with the code a bit and see what you can find…

The problem lies in the case patterns: intersect and complement are intended to be constant patterns, i.e. the SetOp values that argument op would be matched to, but the way the code is written, Scala actually treats them as variable patterns, i.e. they are vals bound to the value of op, whatever it is. On top of that, had op been the only value being matched and the alternatives were simply intersect and complement, like this:

def doSetOp(op: SetOp, sets: Seq[Set[Int]]) = op match {
  case intersect => //...
  case complement => //...
  case _ => //...
}

you’d get a complaint from the compiler that the last two cases are unreachable code, but the way that sets is included in the pattern matching makes all alternatives possible, so the compiler thinks it is all good! Once we understand what is going on here, the fix is simple: just use SetOp.intersect and SetOp.complement as the patterns:

def doSetOp(op: SetOp, sets: Seq[Set[Int]]) = (op, sets) match {
  case (SetOp.intersect, s) if s.size > 1 => s.reduce((s1, s2) => s1.intersect(s2))
  case (SetOp.complement, Seq(s1, s2)) => s1.filterNot(s2.contains)
  case _ => throw new IllegalArgumentException("bad args")
}

Now everything works as expected.

Making Enumerations work with lift-json

Lift-json does not support Enumerations out-of-the-box. The issue is discussed here:

https://groups.google.com/group/liftweb/browse_thread/thread/d38090d804d902a3…

The proposed work-around in the thread is to create a custom serializer:

import net.liftweb.json._
import net.liftweb.json.JsonDSL._

class EnumerationSerializer[E <: Enumeration: ClassManifest](enum: E) extends Serializer[E#Value] {
  val EnumerationClass = classOf[E#Value]
  val formats = Serialization.formats(NoTypeHints)
  def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), E#Value] = {
    case (TypeInfo(EnumerationClass, _), json) => json match {
      case JString(value) => enum.withName(value)
      case value          => throw new MappingException("Can't convert " + value + " to " + EnumerationClass)
    }
  }
  def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
    case i: E#Value => i.toString
  }
}

and use this formats:

implicit val formats = Serialization.formats(NoTypeHints) + new EnumerationSerializer(MyEnum)

This works fine for one Enumeration type but breaks down when there are multiple. That’s because the actual enum type is erased, and the serializer only captures the generic Enumeration#Value type. As a result, when deserializing an object with two or more Enumerations, the wrong enum object will be matched to a name causing a failure to convert the value to an enum (serialization is OK because it just calls toString). So my hack of the hack is:

import net.liftweb.json._
import net.liftweb.json.JsonDSL._

class EnumerationSerializer(enums: Enumeration*) extends Serializer[Enumeration#Value] {
  val EnumerationClass = classOf[Enumeration#Value]
  val formats = Serialization.formats(NoTypeHints)
  def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Enumeration#Value] = {
    case (TypeInfo(EnumerationClass, _), json) => json match {
      case JString(value) => enums.find(_.values.exists(_.toString == value)).get.withName(value)
      case value          => throw new MappingException("Can't convert " + value + " to " + EnumerationClass)
    }
  }

  def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
    case i: Enumeration#Value => i.toString
  }
}

and the formats is:

implicit val formats = Serialization.formats(NoTypeHints) + new EnumerationSerializer(MyEnum, MyOtherEnum)

This version of the EnumerationSerializer stores ALL Enumerations that need to be handled, and when a name needs to be converted, it finds the enum that defines the name and does the conversion.

This works only if the enums do not have common names.

Scala regular expression and pattern matching

Say I have an input string that specifies a numeric range with lower and/or upper bounds. Examples:

">12345"
"<67890"
">12345 and <67899"

I want to parse it to a tuple of (Option[Int], Option[Int]). This can be done easily using regular expression and pattern matching:

def parse(s: String): (Option[Int], Option[Int]) = {
  val gt = """>(d+)""".r
  val lt = """<(d+)""".r
  val between = """>(d+) and <(d+)""".r
  s match {
    case gt(lb) => (Some(lb.toInt), None)
    case lt(ub) => (None, Some(ub.toInt))
    case between(lb, ub) => (Some(lb.toInt), Some(ub.toInt))
    case _ => (None, None)
  }
}

Note how Regex can extract the matched groups in the input. Super convenient.

Getting an existing git repo to svn for use with git-svn

You have a project you’ve been working on in a local git repo. Later on you want to get it to subversion, with the full git history, and work with it using git-svn.

Credit goes to http://jpz-log.info/archives/2009/09/16/start-in-git-push-to-subversion-then-…. I adapted the example to show usage with a standard svn layout.

  1. Create the svn directories:
    svn mkdir --parents http://svn/myproject/trunk
    svn mkdir --parents http://svn/myproject/branches
    svn mkdir --parents http://svn/myproject/tags
  2. Make your git repo track svn by adding to .git/config:
    [svn-remote "svn"]
            url = http://svn
            fetch = myproject/trunk:refs/remotes/trunk
            branches = myproject/branches/*:refs/remotes/*
            tags = myproject/tags/*:refs/remotes/tags/*
  3. Import the (empty!) svn history:
    git svn fetch
  4. Link your current branch (say master) to svn:
    git rebase remotes/trunk
  5. Finally get your git history into svn:
    git svn dcommit

Now you can use git-svn to work with the project!