Buck: Set up Closure Compiler tool chain to minify JavaScript code

Extend the build tool chain to minify JavaScript from CodeMirror
distribution.

Currently SIMPLE_OPTIMIZATIONS mode is used, as ADVANCED_OPTIMIZATIONS
doesn't seem to work.  But even with simple mode the minification factor
is:

393441:cm3-verbose.js
167971:cm3_minified.js

And even more for language modes:

56029:perl-verbose.js
10122:perl-minified.js

Disadvantage: Longer compilation time. In follow-up changes we may want
to optimize it by disabling JS minification in development build.

Change-Id: I24790e84484add4f02b3821cca4b69e62fde0c22
diff --git a/lib/codemirror/BUCK b/lib/codemirror/BUCK
index e56f51c..e8539c6 100644
--- a/lib/codemirror/BUCK
+++ b/lib/codemirror/BUCK
@@ -1,5 +1,6 @@
 include_defs('//lib/maven.defs')
 include_defs('//lib/codemirror/cm3.defs')
+include_defs('//lib/codemirror/closure.defs')
 
 VERSION = '28a638a984'
 SHA1 = '68f8f136092a5965778186fb401a33be34cf73ed'
@@ -8,6 +9,11 @@
 ZIP = 'codemirror-%s.zip' % VERSION
 TOP = 'codemirror-%s' % VERSION
 
+CLOSURE_COMPILER_ARGS = [
+  '--compilation_level SIMPLE_OPTIMIZATIONS',
+  '--warning_level QUIET'
+]
+
 genrule(
   name = 'css',
   cmd = ';'.join([
@@ -23,9 +29,8 @@
   out = 'cm3.css',
 )
 
-# TODO(sop) Minify with Closure JavaScript compiler.
 genrule(
-  name = 'js',
+  name = 'cm3-verbose',
   cmd = ';'.join([
       ':>$OUT',
       "echo '/** @license' >>$OUT",
@@ -36,7 +41,14 @@
      for n in CM3_JS]
   ),
   deps = [':zip'],
-  out = 'cm3.js',
+  out = 'cm3-verbose.js',
+)
+
+js_minify(
+  name = 'js',
+  generated = [':cm3-verbose'],
+  compiler_args = CLOSURE_COMPILER_ARGS,
+  out = 'cm3.js'
 )
 
 prebuilt_jar(
@@ -50,8 +62,13 @@
   name = 'jar',
   cmd = ';'.join([
     'cd $TMP',
-      'unzip -q $(location :zip) %s' %
-      ' '.join(['%s/mode/%s' % (TOP, n) for n in CM3_MODES]),
+    'unzip -q $(location :zip) %s' %
+    ' '.join(['%s/mode/%s' % (TOP, n) for n in CM3_MODES]),
+    ';'.join(['$(exe :js_minifier) ' +
+    ' '.join(CLOSURE_COMPILER_ARGS) +
+    ' --js_output_file %s/mode/%s.min --js %s/mode/%s'
+    % (TOP, n, TOP, n) for n in CM3_MODES]),
+    ';'.join(['mv %s/mode/%s.min %s/mode/%s' % (TOP, n, TOP, n) for n in CM3_MODES]),
     'mkdir net',
     'mv %s net/codemirror' % TOP,
     'mkdir net/codemirror/lib',
diff --git a/lib/codemirror/closure.defs b/lib/codemirror/closure.defs
new file mode 100644
index 0000000..e602b9f
--- /dev/null
+++ b/lib/codemirror/closure.defs
@@ -0,0 +1,50 @@
+# https://code.google.com/p/closure-compiler/wiki/BinaryDownloads?tm=2
+CLOSURE_VERSION = '20140407'
+CLOSURE_COMPILER_URL = 'http://dl.google.com/closure-compiler/compiler-%s.zip' % CLOSURE_VERSION
+COMPILER = 'compiler.jar'
+CLOSURE_COMPILER_SHA1 = 'eeb02bfd45eb4a080b66dd423eaee4bdd1d674e9'
+
+def js_minify(
+    name,
+    out,
+    compiler_args = [],
+    srcs = [],
+    generated = []):
+  cmd = ['$(exe :js_minifier) --js_output_file $OUT'] + compiler_args
+  if srcs:
+    cmd.append('$SRCS')
+  if generated:
+    cmd.extend(['$(location %s)' % n for n in generated])
+
+  genrule(
+    name = name,
+    cmd = ' '.join(cmd),
+    srcs = srcs,
+    out = out,
+)
+
+java_binary(
+  name = 'js_minifier',
+  main_class = 'com.google.javascript.jscomp.CommandLineRunner',
+  deps = [':compiler-jar']
+)
+
+prebuilt_jar(
+  name = 'compiler-jar',
+  binary_jar = ':compiler',
+)
+
+genrule(
+  name = 'compiler',
+  cmd = 'unzip -p $(location :closure-compiler-zip) %s >$OUT' % COMPILER,
+  out = COMPILER,
+)
+
+genrule(
+  name = 'closure-compiler-zip',
+  cmd = '$(exe //tools:download_file)' +
+    ' -o $OUT' +
+    ' -u ' + CLOSURE_COMPILER_URL +
+    ' -v ' + CLOSURE_COMPILER_SHA1,
+  out = 'closure-compiler.zip',
+)