ZSH: How Deep Am I

If you are on unix and you haven’t tried zsh, I would recommend it. If you use zsh and haven’t tried oh-my-zsh,  I would recommend it. I won’t go into too much detail on oh-my-zsh and how it helps manage your zsh configuration, but, it provides two features that make command line work more pleasant. 1) Plugins for integration with things like git, gulp, ruby, etc and 2) a number of different themes.

One of the plugins I use is Gradle. I noticed that it hadn’t been updated for a while because it was missing some switches from newer versions of Gradle, so I updated it. It was a trivial update and while I was there I noticed that the plugin lacked the ability to auto-complete the gradle init command. That is a more complex patch and required me to start learning zsh scripting.

Writing zsh and testing various functions is pretty straight forward–write a function in a file or directly on the command line. Updating configurations (which is what oh-my-zsh manages) is slightly harder to test. The best recommendation that I found, was to just open zsh in zsh.

Screenshot from 2015-12-02 20-00-07

I would open up zsh nested, let oh-my-zsh do its work with my changes and then test. Now I have a shell inside a shell, if I type exit then I’m back to my base shell. If I type exit again then whatever terminal I’m in will shut down. If I got distracted and forgot what level I was at in my nested zsh, and exited, then I had to started my terminal all over again. This is slightly annoying, so I added a little script to my .zshrc file to help me track where I’m at.

export ZSH_LEVEL
let "ZSH_LEVEL++"
print -Pn "\e]2;${ZSH_LEVEL}\a"

function zshexit_shelllevel() {
let "ZSH_LEVEL--"
print -Pn "\e]2;${ZSH_LEVEL}\a"
}
zshexit_functions+=(zshexit_shelllevel)

Let me explain this real quick. Line 3 and 7 will allow us to change the the window title (that’s what the 2 is saying). zshexit_functions is a zsh builtin function that will get called when zsh is exited. So, when the .zshrc get source on start up it increments ZSH_LEVEL and when the zshexit_shelllevel gets called it decrements the ZSH_LEVEL, changing the window title every time.

It looks like this:

levelzsh

See that little “2” in the bottom right-hand corner.

I’m sure there are simpler/better ways to do this, but I got a kick out of learning some simple zsh builtins and display preferences, both of which are used heavily in oh-my-zsh.


 

Edit (March 19, 2016):

As expected, there is a built-in solution for this problem. Check out nath_schwarz solution on reddit.

Weld CDI: User Injected Functionality

Here is the scenario: Suppose you are creating a library that will aggregate data from a system and send that information to standard out. A user may want to use your library to aggregate the same information but wants to send the data elsewhere (eg, a db, a file, etc).  How do you provide these feature to you library without the user having to explicitly create your object and pass in a writer? (Similar to creating an extensible application or plug-in.) You could use Java’s Service Provider but then you would have to programmatically exclude default behavior when users implement their own.

Recently, I’ve been working on an creating an annotation library. In order to create an annotation library in Java, you have to extend an AbstractProcessor and declare that class as a javax.annotation.processing.Processor in META-INF/services. Java will pick this class up automatically, so I need a way inject a users implementation class without changing the code and I want to disable my default implementation when this occurs. In comes Dependency Injection (DI) in the form of JEE’s CDI service.

The following is an example of how to replace one bean implementation with another using CDI. I’m using the JEE reference implementation of CDI, Weld, in an SE fashion. So there is no need to run in a container. The example uses Alternatives to replace a default implementation with a user created implementation. You can find the working example on github.

https://github.com/Scuilion/weldit

The first thing is initializing Weld. Weld requires the base beans.xml file to be in the META-INF folder and because I’m not using an EE container, the container has to be generated manually (Note how the container is created and destroyed before the injected class is used.)

public class Producer {
    @Inject
    Writer writer;
    public someLibraryMethod() {
        Weld weld = new Weld(); 
        WeldContainer container = weld.initialize(); 
        writer = container.instance().select(Writer.class).get(); 
        weld.shutdown(); 
        writer.process();
    }
}

Writer is the interface that you and the consumer of you library will implement. You’re library will come with a default implementation (WriterImpl.java). If the consumer does not create their own implementation then Weld will load up this default.

public class WriterImpl implements Writer {
    @Override
    public void process() {
        System.out.println("in default writer implementation");
    }
}

And here is and example users implementation. All we have to do is use the @Alternative annotation to tell weld that we want to use this class as oppose to the default class to be injected.

@Alternative 
public class ReplacementWriterImpl implements Writer {
    @Override
    public void process() {
        System.out.println("************************");
        System.out.println("in alternative");
        System.out.println("************************");
    }
}

Notice that the only thing different is some extra print statements. Let’s see how this works when running. I’ve set up test for the base and the consumer under com.BaseTest and com.ConsumerTest, respectively. If I run the base test, again with only the default implementation I get the following.

kmb-us-master109:weldit kevin.oneal$ ./gradlew :base:test
:base:compileJava
:base:processResources
:base:classes
:base:compileTestJava
:base:processTestResources
:base:testClasses
:base:test

com.BaseTest > testSomeLibraryMethod STANDARD_OUT
    in default writer implementation

BUILD SUCCESSFUL

Total time: 4.089 secs

And when we run the consumer test, we get the following.

kmb-us-master109:weldit kevin.oneal$ ./gradlew :consumer:test
:base:compileJava UP-TO-DATE
:base:processResources UP-TO-DATE
:base:classes UP-TO-DATE
:base:jar
:consumer:compileJava
:consumer:processResources
:consumer:classes
:consumer:compileTestJava
:consumer:processTestResources UP-TO-DATE
:consumer:testClasses
:consumer:test

com.ConsumerTest > testSomeLibraryMethod STANDARD_OUT
    in consumer
    before called to producer 
    ************************
    in alternative
    ************************
    after called to producer 

BUILD SUCCESSFUL

Total time: 3.971 secs

You can get this project from github under the tag v0.1.

Ultimately, the difference between using the Service Provider or Weld’s interpretation of CDI is that with DI I can eliminate the very trivial default implementation. Although I haven’t tried it, Weld is suppose to allow you to mimic the feature of Service Providers where Java will pick up all implementation of an interface/abstract, just by changing the @Inject variable to take a list.

Using Gradle Setup Info Outside of Gradle

There is a Dev/Ops at my company that is always trying to be clever. His ultimate goal is reduce build times, so I can’t get upset. Recently, he was trying to figure out what project were building and where they were located. He generated this list by making some assumptions about how our Gradle build was determining subprojects and created a script to generate a list of those locations. The problem with that is, if the scheme for subproject generation changed he would have to manually maintain his script.

In comes a little cheat.

Most project that you work on will have more than one subproject. It is good to separate concerns even if all the parts of the project are required to work together. This eliminates pesky problems like circular dependencies, full recompilation, etc. (See, Chapter 57.5) You can use the settings.gradle file to setup a multiproject build. A typical settings.gradle file looks like so: (Actually, this one comes from the Gradle github page.)

include 'distributions'
.
.
.
include 'modelGroovy'
include 'cunit'
include 'platformPlay'
 
rootProject.name = 'gradle'
rootProject.children.each {project ->
    String fileBaseName = project.name
    String projectDirName = "subprojects/$fileBaseName"
    project.projectDir = new File(settingsDir, projectDirName)
    project.buildFileName = "${fileBaseName}.gradle"
}

This is typical of a multiproject build–create a bunch of subprojects and set their properties. In fact, instead of listing each subproject individually, you can set a standard location for projects and resolve them dynamically.

new File("$settingsDir/subprojects/").eachDir {
    include it.name
}

Where include is the method to specify new subprojects.

The goal of the Dev/Ops is to get the list of projects and their locations. There are two ways of accomplishing this task: 1) Create a task in Gradle (that is essentially only a task with a doLast block). 2) Or, use a Groovy script to read the settings file. The problem with the first option is that once your company wide Gradle system starts to grow, so does the configuration time. This configuration time is inconsequential with the respect to the rest of the build. But you might become impatient if all you want is a quick list of projects and project locations. The problem with the second one is that it hacky. But sometimes that fun.

I’ll assume you know how to use Gradle to get this task done and just show the groovy script.

The secret is Groovy Bindings. The script goes in the root directory next to settings.gradle file. It uses bindings to mock out the key pieces that are usually found in the settings file (settindsDir, rootProject, include, project). After creating the mock data you call evaluate on the settings.gradle file. In the end the fake Project object will hold each project.


Binding binding = new Binding()
def workingDir =  new File().getCanonicalPath()

binding.setVariable("settingsDir", workingDir)

binding.setVariable('rootProject', ['name':''])
def include = { component ->
}
def projects = []
def project = {projectName->
    def currentProject = new Project(projectName)
    projects << currentProject 
    
    return  currentProject 
}
binding.setVariable("include", include)
binding.setVariable("project", project)
GroovyShell shell = new GroovyShell(binding)

shell.evaluate(new File(workingDir, 'settings.gradle'))

class Project{
    def name
    def projectDir
    def buildFileName
    def Project(def name){
        this.name = name
    }
}
def getProjects() {
    return projects
}

First Experience with Bintray

When I started to learn Gradle, I wrote a simple plugin. It was a fairly useless adapter for JavaExec. It automatically set up the classpath and created an extension for pointing to the main class. This was a exercise.

project.extensions.create("runSimple", RunSimpleExtension)

project.task('runSimple', type: JavaExec ) {
    project.afterEvaluate{
        main = project.runSimple.mainClass
        classpath = project.sourceSets.main.runtimeClasspath
    }
}

Recently, I’ve been beefing up my development process in Vim and installed Syntastic. This plugin provides syntax checking by running external checkers, two of which I needed–JSHint and javac. Out-of-the-box, Syntastic works great with Java, until you start adding external libraries. Fortunately, I use Gradle on all of my projects and Gradle makes it easy to determine you dependencies.

project.sourceSets.each { srcSet ->
    srcSet.java.srcDirs.each { dir ->
        classpathFiles.add(dir.absolutePath)
    }
}

So I added this functionality to my original plugin and called it gradle-utils. The problem was the hassle of using the plugin from one computer to the next. I’d have to pull the project from GitHub and publish it locally (using the maven-publish plugin). Not to mention if I made changes the whole process would start over.

In Walks jCenter

This was a perfect opportunity to try out BinTray. I’d had an account, but other than signing up, it sat dormant. Here are a list of the things learned while uploading my first artifact.

  • Don’t forget you have to push up your source as well as the complied classes if you want to attach you package to the public jCenter repo. I’m using the gradle maven-publish plugin and accomplish that like so:
    task sourceJar(type: Jar) {
        from sourceSets.main.groovy
        from sourceSets.main.resources
    }
    artifacts {
        archives jar, sourceJar
    }
    publishing {
        publications {
            maven(MavenPublication) {
                from components.java
                artifact sourceJar {
                    classifier "sources"
                }
            }
        }
    }
    
  • Gradle 2.1’s new developer plugin index makes include the Bintray plugin a snap. (Example of this below.)
  • In order to include your package in the the publicly accessible jCenter you have to ask. It took me longer than I would like to admit to find how to do this. I assumed that the option would be located somewhere within the package you were attempting to release, but it actually on the home page of jCenterbintray

A Personal Plugin for Personal Use

This plugin is very “me” centric, but it’s really easy to get it setup, assuming you already have the Syntastic plugin working in Vim. There are two things you need, 1) set Syntastic so that it creates a config file, and 2) add the gradle-utils plugin to your build.gradle file.

1) .vimrc

let g:syntastic_java_checkers=['checkstyle', 'javac']
let g:syntastic_java_javac_config_file_enabled = 1

2) build.gradle

buildscript {
    repositories {
      jcenter()
    }
    dependencies {
       classpath group: 'com.scuilion.gradle', name: 'utils', version: '0.2'
    }
}
apply plugin: 'utils'

Note: This is a post process plugin and should be applied at the end of your build file.

Screenshot from 2014-07-19 17:18:02
When junit is commented out of the build file, Syntastic shows that it can’t compile this particular file.

An aside: I used Gradle 2.1’s developer index to include the BinTray plugin. So instead of:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.5"
    }
}
apply plugin: "com.jfrog.bintray"
plugins {
    id "com.jfrog.bintray" version "0.5"
}

Pretty cool!