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
36
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
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
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 }