View Javadoc
1   package com.simpligility.maven.plugins.android.compiler;
2   
3   import com.google.api.client.repackaged.com.google.common.base.Strings;
4   import com.google.common.base.Predicate;
5   import com.google.common.collect.Iterables;
6   import java.io.BufferedReader;
7   import java.io.File;
8   import java.io.FileWriter;
9   import java.io.IOException;
10  import java.io.PrintWriter;
11  import java.io.StringReader;
12  import java.io.StringWriter;
13  import java.io.Writer;
14  import java.util.ArrayList;
15  import java.util.Arrays;
16  import java.util.List;
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  import org.codehaus.plexus.compiler.AbstractCompiler;
20  import org.codehaus.plexus.compiler.CompilerConfiguration;
21  import org.codehaus.plexus.compiler.CompilerException;
22  import org.codehaus.plexus.compiler.CompilerMessage;
23  import org.codehaus.plexus.compiler.CompilerMessage.Kind;
24  import org.codehaus.plexus.compiler.CompilerOutputStyle;
25  import org.codehaus.plexus.compiler.CompilerResult;
26  import org.codehaus.plexus.component.annotations.Component;
27  import org.codehaus.plexus.util.IOUtil;
28  import org.codehaus.plexus.util.cli.CommandLineException;
29  import org.codehaus.plexus.util.cli.CommandLineUtils;
30  import org.codehaus.plexus.util.cli.Commandline;
31  import org.codehaus.plexus.util.cli.StreamConsumer;
32  import org.codehaus.plexus.util.cli.WriterStreamConsumer;
33  
34  /**
35   * @plexus.component role="org.codehaus.plexus.compiler.Compiler"
36   * role-hint="jack"
37   */
38  @Component( role = Compiler.class, hint = "jack" )
39  public class JackCompiler extends AbstractCompiler
40  {
41  
42      private static final Log LOG = LogFactory.getLog( JackCompiler.class );
43      
44      public static final String JACK_COMPILER_ID = "jack";
45      
46      public JackCompiler()
47      {
48          super( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES, ".java", ".dex", null );
49      }
50  
51      @Override
52      public String[] createCommandLine( CompilerConfiguration cc ) throws CompilerException
53      {
54          String androidHome = System.getenv( "ANDROID_HOME" );
55          String jackJarPath = androidHome + "/build-tools/24.0.2/jack.jar";
56          String androidJarPath = androidHome + "/platforms/android-24/android.jar";
57          String command =
58          
59              ( "java -jar " + jackJarPath + " "
60              + " -D jack.java.source.version=" + cc.getSourceVersion()
61              + " --classpath " + androidJarPath
62              + " --output-dex " + cc.getBuildDirectory()
63              + " src/main/java/ target/generated-sources/r/" );
64  
65          LOG.debug( String.format( " jack command : %s", command ) );
66          
67          return trim( command.split( "\\s" ) ) ;
68      }
69  
70      @Override
71      public boolean canUpdateTarget( CompilerConfiguration configuration )
72              throws CompilerException
73      {
74          return false;
75      }
76  
77      @Override
78      public CompilerResult performCompile( CompilerConfiguration configuration ) throws CompilerException
79      {
80          String[] commandLine = this.createCommandLine( configuration );
81          
82          List<CompilerMessage> messages = compileOutOfProcess( configuration.getWorkingDirectory(), 
83                                                configuration.getBuildDirectory(), 
84                                                commandLine[ 0 ], 
85                                                Arrays.copyOfRange( commandLine, 1, commandLine.length )
86              );
87  
88  
89          return new CompilerResult().compilerMessages( messages );
90  
91      }
92  
93      @Override
94      public String getOutputFile( CompilerConfiguration configuration ) throws CompilerException
95      {
96          return "classes.dex";
97      }
98  
99      
100     @SuppressWarnings( "deprecation" )
101     private List<CompilerMessage> compileOutOfProcess( File workingDirectory, File target, String executable,
102             String[] args )
103             throws CompilerException
104     {        // ----------------------------------------------------------------------
105         // Build the @arguments file
106         // ----------------------------------------------------------------------
107 
108         File file;
109 
110         PrintWriter output = null;
111 
112         try
113         {
114             file = new File( target, "jack-argmuents" );
115 
116             output = new PrintWriter( new FileWriter( file ) );
117 
118             for ( String arg : args )
119             {
120                 output.println( arg );
121             }
122         } 
123         catch ( IOException e )
124         {
125             throw new CompilerException( "Error writing arguments file.", e );
126         } 
127         finally
128         {
129             IOUtil.close( output );
130         }
131 
132         // ----------------------------------------------------------------------
133         // Execute!
134         // ----------------------------------------------------------------------
135         Commandline cli = new Commandline();
136 
137         cli.setWorkingDirectory( workingDirectory.getAbsolutePath() );
138 
139         cli.setExecutable( executable );
140 
141         cli.addArguments( args );
142         
143         Writer stringWriter = new StringWriter();
144 
145         StreamConsumer out = new WriterStreamConsumer( stringWriter );
146 
147         StreamConsumer err = new WriterStreamConsumer( stringWriter );
148 
149         int returnCode;
150 
151         List<CompilerMessage> messages;
152 
153         try
154         {
155             returnCode = CommandLineUtils.executeCommandLine( cli, out, err );
156 
157             messages = parseCompilerOutput( new BufferedReader( new StringReader( stringWriter.toString() ) ) );
158         } 
159         catch ( CommandLineException e )
160         {
161             throw new CompilerException( "Error while executing the external compiler.", e );
162         } 
163         catch ( IOException e )
164         {
165             throw new CompilerException( "Error while executing the external compiler.", e );
166         }
167 
168         if ( returnCode != 0  )
169         {            
170             StringBuilder errorBuilder = new StringBuilder();
171             for ( CompilerMessage message : messages ) 
172             {
173                 errorBuilder.append( message.getMessage() );
174             }
175             
176             
177             throw new CompilerException( errorBuilder.toString() );
178         }
179 
180         return messages;
181     }
182 
183     public static List<CompilerMessage> parseCompilerOutput( BufferedReader bufferedReader )
184             throws IOException
185     {
186         List<CompilerMessage> messages = new ArrayList<CompilerMessage>();
187 
188         String line = bufferedReader.readLine();
189 
190         while ( line != null )
191         {
192             messages.add( new CompilerMessage( line, Kind.NOTE ) );
193 
194             line = bufferedReader.readLine();
195         }
196 
197         return messages;
198     }
199 
200     private String[] trim( String[] split ) 
201     {
202         Iterable<String> filtered = Iterables.filter( 
203                 Arrays.asList( split ), 
204                 new Predicate<String>() 
205                 {
206                     @Override
207                     public boolean apply( String t ) 
208                     {
209                         return !Strings.isNullOrEmpty( t );
210                     }
211                 }
212         );
213         
214         return Iterables.toArray( filtered, String.class );
215     }
216 
217 }