<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yannick&#039;s Java Tech Blog</title>
	<atom:link href="http://welsch.lu/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://welsch.lu/blog</link>
	<description></description>
	<lastBuildDate>Sat, 31 Jan 2015 13:22:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.2.18</generator>
	<item>
		<title>Gradle Bash integration for multi-project builds</title>
		<link>http://welsch.lu/blog/2015/01/gradle-bash-integration-for-multi-project-builds/</link>
		<comments>http://welsch.lu/blog/2015/01/gradle-bash-integration-for-multi-project-builds/#comments</comments>
		<pubDate>Sat, 31 Jan 2015 13:19:11 +0000</pubDate>
		<dc:creator><![CDATA[ywelsch]]></dc:creator>
				<category><![CDATA[bash]]></category>
		<category><![CDATA[gradle]]></category>

		<guid isPermaLink="false">http://welsch.lu/blog/?p=5</guid>
		<description><![CDATA[Working on Gradle-based enterprise builds requires familiarity with the usually quite large number of different project-specific tasks. Some sub-projects provide custom tasks to run maintenance scripts, others tasks to check additional properties of the build or to start and stop different components needed for the development life-cycle. Bash auto-completion helps with the burden of remembering &#8230; ]]></description>
				<content:encoded><![CDATA[<p>Working on Gradle-based enterprise builds requires familiarity with the usually quite large number of different project-specific tasks. Some sub-projects provide custom tasks to run maintenance scripts, others tasks to check additional properties of the build or to start and stop different components needed for the development life-cycle.</p>
<p>Bash auto-completion helps with the burden of remembering all the different tasks for the various sub-projects in a build. It also provides new ways to discover the features of a build in an exploratory way. In the following, I give a description on how to implement bash auto-completion, based on the following requirements:</p>
<ul>
<li>Fast auto-completion in the sub-second range. To compute the auto-completable suggestions, the Gradle project needs to be fully configured, which takes at least a few seconds for medium-sized builds. This means that the list of auto-completable suggestions needs to be precomputed.</li>
<li>The auto-completable suggestions to show should be customizable. Some tasks, even if available on the project, should perhaps not be shown. This might be tasks that are not relevant for the developer but used in later integration stages. Other parameters to the build might be interesting to show in addition to the restricted set of tasks. This might include other parameters that can be passed to the Gradle build, such as task parameters or options to set the Gradle output logging level.</li>
<li>No change to the Gradle wrapper scripts are needed.</li>
</ul>
<p>The solution presented is two-fold. First, we introduce the shorthand <code>gr</code> to run the Gradle wrapper from any directory of the multi-project build. Auto-completion is then implemented in the second step. Note that, although Bash is a Unix shell, the following also works for Bash ports on Windows such as MSYS (part for example of <a href="https://msysgit.github.io/">msysGit</a>).</p>
<h1>Gradle shorthand <code>gr</code></h1>
<p>There are different design choices to implement the shorthand <code>gr</code>, influenced by the features it should have. The implementation given here works as follows. It searches from the current directory upward until it finds a Gradle wrapper script which it then invokes.</p>
<p>We first implement the function <code>upsearch</code> that can search upward in a directory tree. All of the following goes into the Bash startup file <code>~/.bashrc</code>:</p>
<pre class="brush: bash; title: ; notranslate">
upsearch () { # adapted from https://gist.github.com/lsiden/1577473
  local the_test=$1
  local curdir=`pwd`

  while [[ &quot;`pwd`&quot; != '/' ]]; do
    if eval &quot;[[ $the_test ]]&quot;; then
      pwd
      cd &quot;$curdir&quot;
      return 0
    fi
    cd ..
  done
  cd &quot;$curdir&quot;
  return 1
}
</pre>
<p>We then implement a function <code>_findgradledir</code> that searches for the Gradle wrapper file named <code>gradlew</code>:</p>
<pre class="brush: bash; title: ; notranslate">
_findgradledir () {
  upsearch '-f gradlew'
}
</pre>
<p>The function <code>_gradlew</code>, implemented in the following, uses <code>_findgradledir</code> to find the wrapper file, which it then invokes.</p>
<pre class="brush: bash; title: ; notranslate">
_gradlew () {
  local gradle_project_dir=`_findgradledir`
  if [ -z &quot;$gradle_project_dir&quot; ]; then
    echo &quot;Gradle project directory not found&quot; 1&gt;&amp;2
    return 1
  fi
  &quot;$gradle_project_dir/gradlew&quot; -p &quot;$gradle_project_dir&quot; &quot;$@&quot;
}
</pre>
<p>Last, we define the command <code>gr</code>. Its implementation is directly given by the function <code>_gradlew</code>. We can also pass default parameters to the wrapper invocation. For example, to improve startup and execution time of the Gradle invocation, we add the <code>--daemon</code> flag that activates the <a href="https://gradle.org/docs/current/userguide/gradle_daemon.html">Gradle daemon</a>:</p>
<pre class="brush: bash; title: ; notranslate">
alias gr=&quot;_gradlew --daemon&quot;
</pre>
<h1>Auto-completion</h1>
<p>Implementing auto-completion requires not only some bash scripting but also some implementation on the Gradle side that gives us the list of auto-completable suggestions. We introduce a task named <code>bashCompletion</code> that generates the list of tasks in a multi-project build and writes them line-by-line into a text file. The <code>bashCompletion</code> task is defined in the root Gradle project (but could be put for example in an <a href="https://gradle.org/docs/current/userguide/init_scripts.html">init script</a> if it were to be used for many builds):</p>
<pre class="brush: groovy; title: ; notranslate">
task bashCompletion &lt;&lt; {
  def allTaskNames = []
  getAllTasks(true).each { proj, taskSet -&gt;
    taskSet.each {
      if (proj.parent) {
        allTaskNames += proj.name + ':' + it.name
      } else {
        allTaskNames += it.name
      }
    }
  }
  def commands = (defaultGradleCommands + allTaskNames).sort().unique().join('\n')
  file('gradle-autocomplete').text = commands
}
</pre>
<p>The presented implementation is a very basic one and many customizations are possible here. For example, task exclusion lists or other build parameters could be used. The auto-completable suggestions are stored sorted in a line-based text file so that it has a nice format for diffs when we put it into version control. More information on why this might be useful is provided in another blog article <a href="http://welsch.lu/blog/2015/01/integrating-gradle-with-eclipse/" title="Integrating Gradle with Eclipse for larger teams">here</a>.</p>
<p>On the Bash side (<code>~/.bashrc</code>), basic auto-completion is fairly trivial to implement. We use the previously defined function <code>_findgradledir</code> to find the text file of auto-completable suggestions created by our <code>bashCompletion</code> task:</p>
<pre class="brush: bash; title: ; notranslate">
_gradle_complete()
{
  local cur
  _get_comp_words_by_ref -n : cur

  local gradle_project_dir=`_findgradledir`
  if [ -z &quot;$gradle_project_dir&quot; ]; then
    return 1
  fi
  
  if [ ! -f &quot;$gradle_project_dir/gradle-autocomplete&quot; ]; then
    return 1
  fi
  
  local commands=$(cat &quot;$gradle_project_dir/gradle-autocomplete&quot; | tr '\n' ' ')
  COMPREPLY=( $(compgen -W &quot;$commands&quot; -- $cur) )
  __ltrim_colon_completions &quot;$cur&quot;
}
</pre>
<p>The line <code>_get_comp_words_by_ref -n : cur</code> is needed for bash completion to work with colons in task calls of sub-projects.</p>
<p>Finally we use the bash <code>complete</code> command to attach the implemented bash completion function to our Gradle shorthand <code>gr</code>:</p>
<pre class="brush: bash; title: ; notranslate">
complete -F _gradle_complete gr
</pre>
]]></content:encoded>
			<wfw:commentRss>http://welsch.lu/blog/2015/01/gradle-bash-integration-for-multi-project-builds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integrating Gradle with Eclipse for larger teams</title>
		<link>http://welsch.lu/blog/2015/01/integrating-gradle-with-eclipse/</link>
		<comments>http://welsch.lu/blog/2015/01/integrating-gradle-with-eclipse/#comments</comments>
		<pubDate>Sat, 17 Jan 2015 11:45:52 +0000</pubDate>
		<dc:creator><![CDATA[ywelsch]]></dc:creator>
				<category><![CDATA[eclipse]]></category>
		<category><![CDATA[gradle]]></category>

		<guid isPermaLink="false">http://welsch.lu/blog/?p=13</guid>
		<description><![CDATA[Integrated Desktop Environments such as Eclipse, IDEA or NetBeans are necessary development tools nowadays to comfortably develop large-scale Java software. The actual production build is however usually done using build tools such as Maven, Ant or Gradle. A seamless integration between build tool and IDE is thus a key factor to connect various stages of &#8230; ]]></description>
				<content:encoded><![CDATA[<p>Integrated Desktop Environments such as Eclipse, IDEA or NetBeans are necessary development tools nowadays to comfortably develop large-scale Java software. The actual production build is however usually done using build tools such as Maven, Ant or Gradle. A seamless integration between build tool and IDE is thus a key factor to connect various stages of the development lifecycle, especially in larger teams. In the following, I present a recipe to integrate the Gradle build system with the Eclipse IDE. It is a solution I believe to work very well for medium-sized to large teams and which I have implemented at my workplace.</p>
<p>As usual, the given solution is based on a specific set of requirements:</p>
<ul>
<li>Gradle and Eclipse build configurations should be kept in sync. Consistency between IDE settings and build system ensures that the development environment is as close as possible to the final software build.</p>
</li>
<li>
<p>The overhead of keeping things consistent should be low.</p>
</li>
<li>
<p>Developers should not require to install any Eclipse plugins such as the <a href="https://github.com/spring-projects/eclipse-integration-gradle/">STS Gradle integration</a>.</p>
</li>
<li>
<p>Complex installation or configuration processes should not be required by the developer to get the Eclipse IDE properly set up.</p>
</li>
<li>
<p>The version control system should contain all relevant information to directly start developing without doing any complicated installation or configuration. This should especially allow to evolve the infrastructure in sync with the code.</p>
</li>
</ul>
<p>The solution I outline has two aspects:</p>
<p>1) Managing and generating all relevant Eclipse settings using Gradle.<br />
2) Putting the generated Eclipse settings into the version control system.</p>
<h1>Managing Eclipse settings using Gradle</h1>
<p>There are numerous advantages to manage Eclipse settings using Gradle:</p>
<ul>
<li>Many properties can be kept in sync between Gradle and Eclipse. Such properties include source and target levels for the compiler, encoding of source files and classpath settings.</li>
<li>In large multi-project builds, sharing configurations over many sub-projects can happen quite frequently. This is a task that should be easy to do. Gradle supports this nicely using its pattern of <em>configuration as code</em>. Common settings that are frequently used by many sub-projects can be abstracted into closures. These closures, which can be customized to one&#8217;s need, can then be applied to all relevant sub-projects. By managing the Eclipse configurations in Gradle, the same kind of customization and sharing can be done for Eclipse-related settings as well. In fact, this is not only limited to properties that are shared between Gradle and Eclipse. It is useful to manage other Eclipse configurations such as auto-save actions for the Eclipse editor or formatting rules for the Eclipse formatter. These settings can be configured on a per-project basis and do not require any changes to the Eclipse installation. It ensures that all developers submit properly formatted source-code independently on what they have configured in their Eclipse installation. It also gives them the possibility to dynamically evolve settings along with the source code without requiring any other provisioning framework.</li>
</ul>
<h1>Eclipse settings under version control</h1>
<p>Putting Eclipse settings under version control might seem at odds with the principle of not putting derived resources into version control. One reason for this is the need of additional storage costs in the version control system. In this specific case, however, things are not that bad. Eclipse settings are stored in text files taking not much space and are line-based which is very good for diffs. Another challenge is that consistency cannot be guaranteed between sources and derived resources. This risk can be mitigated by using a Continuous Integration server which checks for consistency after each push. This is simply realized by checking for uncommitted changes in the workspace after regenerating the Eclipse files using <code>gradle cleanEclipse eclipse</code>. A Gradle-based implementation of this check for the Git version control system is provided at the end of the blog post.</p>
<p>The main reasons for why we put the Eclipse settings into version control are as follows:</p>
<ul>
<li>In our case, running the command <code>gradle eclipse</code> takes 10+ seconds (mostly due to a longer configuration-phase of the build), which is too slow as a post-checkout hook.</li>
<li>It ensures that every developer is always using the correct classpath when updating or switching branches. Additionally, it does not require to regenerate the settings each time a checkout occurs. Checkouts occur way more frequently than changes to the settings!</li>
<li>The developer becomes aware of unintended changes made to his Eclipse configurations (configuration file gets marked as dirty by the version control system and consistency is enforced by the integration server).</li>
</ul>
<p>Using the given solution, it is then the responsibility of developers that make changes to the settings, for example by adding new third-party libraries, to run <code>gradle eclipse</code> and to check the updated Eclipse setting files into version control.</p>
<p>A critical requirement for the solution to work is that the generated Eclipse configurations are neither machine- nor developer-specific. In the following, I present some implementation tips that ensure this for the three Eclipse settings files that are generated when invoking the Gradle <code>eclipse</code> task:</p>
<pre class="brush: bash; title: ; notranslate">
.project
.setting/.org.eclipse.jdt.core.prefs
.classpath
</pre>
<h1>Implementation tips</h1>
<p>The project settings file is stored in <code>xml</code> format and is easily portable. It needs no further consideration. The jdt core preferences file is a Java Properties file (without the file ending <code>.properties</code>) and contains, among others, compilation settings. The issue with the Gradle generation of this file is that it is not deterministic. The generated properties file has as first line a commented time stamp which gets updated whenever <code>gradle eclipse</code> is called. To make things worse, the elements in the file are not sorted. We fix this by adding a post-action to the <code>eclipseJdt</code> task:</p>
<pre class="brush: groovy; title: ; notranslate">
eclipseJdt &lt;&lt; {
  def lines = outputFile.text.readLines().findAll { !it.startsWith('#') }
  outputFile.text = lines.sort().collect{ it + '\n' }.join()
}
</pre>
<p>After the settings file has been generated by <code>eclipseJdt</code>, we load the content of the file, remove the auto-generated time stamp which is prefixed with the comment symbol <code>#</code>, and finally sort the remaining options.</p>
<p>To ensure that the generation process of the classpath file is deterministic, we also require that the ordering of classpath items is fixed. Note that no formal guarantees regarding classpath ordering are given by the Gradle developers. What we could observe so far, however, is that the ordering is mostly deterministic with a few exceptions. By fixing these few exceptional cases, we can assume that the generation is fully deterministic (If it is not the case, we can easily detect this using our continuous integration server).</p>
<p>One particular exception is the use of <code>*</code> includes. For example, using</p>
<pre class="brush: groovy; title: ; notranslate">
compile fileTree(dir: 'lib', include: '*.jar')
</pre>
<p>gives a different ordering of files across different systems. This can be fixed by sorting the dependencies using</p>
<pre class="brush: groovy; title: ; notranslate">
compile files { fileTree(dir: 'lib', include: '*.jar').files.sort() }
</pre>
<p>instead.</p>
<p>Managed dependencies are stored in the Gradle dependency cache, which is usually located under the home directory of the current user. To get a user-independent classpath, Gradle can be instructed to replace the prefix to the Gradle cache by a named variable:</p>
<pre class="brush: groovy; title: ; notranslate">
eclipse.pathVariables 'GRADLE_USER_HOME': gradle.gradleUserHomeDir
</pre>
<p>Note that this also works for the corresponding source jars, <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=67020">but not for Javadoc</a>. Two things then need to be communicated to the other developers. First, the variable <code>GRADLE_USER_HOME</code> has to be set in the Eclipse IDE settings menu which can be accessed through Window -&gt; Preferences -&gt; Java -&gt; Build Path -&gt; Classpath Variables. To remind the developer of this, a message can be written to the console whenever the Eclipse classpath is (re-)generated.</p>
<pre class="brush: groovy; title: ; notranslate">
gradle.taskGraph.whenReady { taskGraph -&gt;
  if (!taskGraph.allTasks.findAll{ it.name == 'eclipseClasspath' }.empty) {
    gradle.buildFinished {
      println '----------------------------------------------------------------------'
      print   &quot;Please set the Eclipse classpath variable 'GRADLE_USER_HOME' in Preferences &quot;
      println &quot;-&gt; Java -&gt; Build path -&gt; Classpath Variable to $gradle.gradleUserHomeDir&quot;
      println '----------------------------------------------------------------------'
    }
  }
}
</pre>
<p>Second, the interaction of the presented approach with software repositories (Maven Central or a company-local repository using software such as Nexus or Artifactory) must be understood. After checking out code, the developer has an up-to-date Eclipse classpath file. It does not ensure, however, that the developer has all the required libraries in his Gradle cache which are referenced from the Eclipse classpath file. After doing the check out, the developer might thus see a warning in Eclipse showing that some classpath items are missing. In that case, the developer simply re-executes <code>gradle eclipse</code> to regenerate the Eclipse settings (which should leave the settings files unchanged) and as side-effect downloads the missing libraries.</p>
<p>Non-managed dependencies also need special care. As Jar files are sometimes stored directly in Git along with their projects, we have to ensure that relative paths to these files are used to guarantee a user-independent classpath. The Gradle eclipse plugin unfortunately generates absolute paths. We fix this in the following way:</p>
<pre class="brush: groovy; title: ; notranslate">
eclipse.classpath.file.whenMerged { classpath -&gt;
  classpath.entries.each { entry -&gt;
    if (entry.kind == 'lib') {
      // for jar files referenced in project folder, use relative path
      def prefix = projectDir.absolutePath.replace('\\', '/')
      entry.path = entry.path.replace(prefix, &quot;/$eclipse.project.name&quot;)
    }
  }
}
</pre>
<p>For Windows compatibility reasons, we have to normalize the project path by replacing backward by forward slashes. The code is best illustrated using an example: The classpath entry for the JUnit library located in <code>/home/foo/bar/XYZ/lib/junit.jar</code> of project <code>XYZ</code> is converted to <code>/XYZ/lib/junit.jar</code> (which is the relative path format understood by Eclipse).</p>
<p>One last thing: To ensure that the generated setting files are kept in sync with their definitions in Gradle, a task can be created that checks for uncommitted changes whenever the files are recreated. The Java implementation of Git called JGit makes this a simple and portable task:</p>
<pre class="brush: groovy; title: ; notranslate">
buildscript {
  repositories {
    mavenCentral()
  }

  dependencies {
    classpath 'org.eclipse.jgit:org.eclipse.jgit:3.6.0.201412230720-r'
  }
}

task checkUncommittedChanges &lt;&lt; {
  def repoDir = file('.') // root of the Git repository
  def gitRepo = org.eclipse.jgit.api.Git.open(repoDir)
  def uncommittedChanges = gitRepo.status().call().getUncommittedChanges()
  gitRepo.close()
  if (uncommittedChanges.size() &gt; 0) {
    ant.fail &quot;Uncommitted changes check failed. Uncommitted changes found: $uncommittedChanges&quot;
  }
}
</pre>
<p>The continuous integration server can then simply execute <code>gradle cleanEclipse eclipse checkUncommittedChanges</code> to check for inconsistencies.</p>
<p>This concludes the blog post. Future expansions into the topic might focus more on what specific Eclipse settings to manage using Gradle and what other settings to leave open for developers to customize to their needs. Any comments or suggestions are very welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://welsch.lu/blog/2015/01/integrating-gradle-with-eclipse/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
