Thursday, November 24, 2011

Quickly find and open files

I frequently need to find a file that is located deep within the current directory and operate on it -- like opening in vim or svn diffing it.  I can never remember the exact path to the file, and sometimes can't even remember the full name.  All I know is that the file is somewhere within the current directory and its sub-directories.  So, I end up running the UNIX find command, and then cut-pasting the returned file path into the command of the interest.  This wastes time.  So I wrote a small python script to make it easier.

Copy the script f.py (located at the end of the post) into some directory that is on your PATH.  Suppose you are looking for the file that starts with Foo, you just run:

$ f.py Foo*
1) ./subdir1/subdir2/Foo1.java
2) ./subdir1/Foo.java
Enter file number:

Enter the number of the file you are interested in.  That will bring up the following menu of operations you can perform on the selected file.

Process ./subdir1/subdir2/Foo1.java
1. vim
2. emacs
3. svn add
4. svn diff
5. open (OSX only)
Enter choice (Default is 1):

If the pattern you specify matches only a single file, the script directly jumps to the operation selection menu.  Hope this will save you some key-strokes.

#!/usr/bin/python
# This program is used to easily locate a file matching 
# the user specified pattern within the current directory
# and to quickly perform some common operations (like
# opening it in vim) against it.
import subprocess
import sys
import os

def processFile(fileName):
    """
    Show the user the possible actions with the specified file,
    and prompt the user to select a particular action.

    """

    fileName = fileName.strip()
    print "Process %s" % fileName
    print "1. vim"
    print "2. emacs"
    print "3. svn add"
    print "4. svn diff"
    print "5. open (OSX only)"

    choice = raw_input("Enter choice (Default is 1):").strip()
    
    if choice == "1" or choice == "":
        cmd = "vim %s" % fileName
    elif choice == "2":
        cmd = "emacs %s" % fileName
    elif choice == "3":
        cmd = "svn add %s" % fileName
    elif choice == "4":
        cmd = "svn diff %s" % fileName
    elif choice == "5":
        cmd = "open %s" % fileName
    print cmd
    os.system(cmd)


def listFiles(fileNames):
    """ 
    Show the list of files and prompt user to select one 
    """

    fileIndex = 1
    for fileName in fileNames:
        print "%d) %s" % (fileIndex, fileName.strip())
        fileIndex += 1
    choice = raw_input("Enter file number:")
    chosenFileName = fileNames[int(choice)-1].strip()
    processFile(chosenFileName)


if __name__ == "__main__":

    if len(sys.argv) < 2:
        print "Usage: f.py FILE_PATTERN_OF_INTEREST"
        sys.exit(-1)

    pattern = sys.argv[1]
    proc = subprocess.Popen("find . -name \"%s\" | grep -v svn" % pattern, 
        shell=True, stdout=subprocess.PIPE)
    lines = proc.stdout.readlines()
    if len(lines) == 0:
        print "No matching files found. Note you can use wild cards like *"
    elif len(lines) == 1:
        processFile(lines[0])
    else:
        listFiles(lines)


Wednesday, November 09, 2011

Automatically create Eclipse projects for your Scala projects using sbt

In my previous post, I described the bare minimum you need to know to get started using sbt.  In this post, I will describe how sbt can be used to automatically create the .project and .classpath files you need to create for loading your project into the Eclipse IDE. Using sbt to create your Eclipse project files ensures that they are always in sync with your build definition. And of course, it saves a lot of the clicks or key strokes need to manually specify classpaths in Eclipse.

Step 1
Install the Eclipse plugin for Scala, if you don't already have it installed.
Step 2
Add the following lines to myproject/project/plugins/build.sbt. This tells sbt that you want to use the sbteclipse plugin. Note that this build.sbt is different from the build.sbt at the top level of your project, i.e. in myproject/ directory.
resolvers += Classpaths.typesafeResolver

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse" % "1.4.0")
Step 3
From the myproject/ directory, type
sbt "eclipse create-src"
This step will create the .project and .classpath files required by Eclipse inside the myproject/ directory.
Step 4
Import the project into Eclipse. Following the menu File > Import > General > Existing Projects into Workspace and browse to myproject

Tuesday, November 08, 2011

Quick Start to using Scala Simple Build Tool (sbt)

After you finish a basic Hello World program in Scala, and want to start your first real Scala project, you will need to choose a build tool.  While you can use tools like ant or maven, Simple Build Tool (sbt in short) is a very popular option among Scala programmers.  In this post, I describe the bare minimum you need to know to quickly get started on using sbt.

Step 1: Install sbt
On a Mac it is as simple as 
sudo port install sbt
or, if you are using homebrew,
brew install sbt
For other operating systems, please see the official Getting Started Setup page.

Step 2: Create your project's directory structure
myproject/
    src/
        main/
            scala/
            java/
            resources/
        test/
            scala/
            java/
            resources/
myproject is your project's top-level directory. resources contain non-code files that are packaged up together with your project, like image or data files.

Step 3: Start writing your project's code
Let's just use a Hello World program.  Create myproject/src/main/scala/HelloWorld.scala that contains the following code:
import org.slf4j._

object HelloWorld {
    def main(args: Array[String]) = {
        val logger:Logger = LoggerFactory.getLogger("MyLogger");
        logger.info("Hello World");
    }
}
We use the slf4j logging library instead of a simple println in order to demonstrate how external dependencies are specified in sbt.

Step 4: Create a build definition file
Put the following lines in myproject/build.sbt. Note that the blank lines below ARE absolutely necessary.
name := "Hello World"

version := "1.0"

scalaVersion := "2.9.1"

libraryDependencies ++= Seq(
  "org.slf4j" % "slf4j-api" % "1.6.4",
  "org.slf4j" % "slf4j-simple" % "1.6.4"
)
The libraryDependencies setting specifies the managed dependencies, i.e., the dependencies which are automatically downloaded for you from the Maven repositories. A dependency is specified as groupId % artifactId % revision. Conventions for groupId, artifactId and revision are discussed at http://maven.apache.org/guides/mini/guide-naming-conventions.html. The automatically downloaded dependencies are usually stored in ~/.ivy2/cache.

You don't have to use maven if you don't want to. Instead you can use unmanaged dependencies. Just put the appropriate jars in myproject/lib, and don't specify them in the libraryDependencies setting.

Step 5: Compile, run and package your program
cd myproject
sbt run
The first time you run sbt, it will download all the dependencies (sometimes including the scala version specified in the scalaVersion setting). This means that it will take some time. Subsequent runs will be much faster.

If you just want to compile,  type:
sbt compile
You can set up sbt to automatically compile your program as soon as any source file changes.  To do so, type:
sbt ~compile
Continuous compilation is a great time-saver.

To package your program for distribution as a jar, type:
sbt package
A jar containing all your compiled classes and resources from myproject/src/main/resources will be found in myproject/target/scala-YOUR_SCALA_VERSION_HERE. Note that dependencies are NOT included in the jar. To include all dependencies into the output jar, you will need to use the assembly plugin. See the next step for pointers to info about plugins.

Step 6: Read the official Getting Started Guide
This post only aims to get you quickly started on sbt.  There are tons of features it does not cover -- multiple projects and plugins, just to name two very important ones.  To learn how to use these features and to understand the fundamental principles behind sbt (which is in fact just a Scala Domain Specific Language), please read the Official Getting Started Guide.  It is long and sometimes too deep, but very useful indeed.