Coverage Report - org.codehaus.plexus.compiler.j2objc.J2ObjCCompiler
 
Classes in this File Line Coverage Branch Coverage Complexity
J2ObjCCompiler
0%
0/90
0%
0/44
4,75
 
 1  
 package org.codehaus.plexus.compiler.j2objc;
 2  
 
 3  
 /*
 4  
  * Copyright 2005 The Apache Software Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *      http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 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.util.StringUtils;
 27  
 import org.codehaus.plexus.util.cli.CommandLineException;
 28  
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 29  
 import org.codehaus.plexus.util.cli.Commandline;
 30  
 import org.codehaus.plexus.util.cli.StreamConsumer;
 31  
 import org.codehaus.plexus.util.cli.WriterStreamConsumer;
 32  
 
 33  
 import java.io.BufferedReader;
 34  
 import java.io.File;
 35  
 import java.io.IOException;
 36  
 import java.io.StringReader;
 37  
 import java.io.StringWriter;
 38  
 import java.io.Writer;
 39  
 import java.util.ArrayList;
 40  
 import java.util.Arrays;
 41  
 import java.util.List;
 42  
 import java.util.Map;
 43  
 
 44  
 /**
 45  
  * A plexus compiler which use J2ObjC . It is derived from the CSharpCompiler to
 46  
  * compile with J2ObjC.
 47  
  *
 48  
  * @author <a href="mailto:ludovic.maitre@effervens.com">Ludovic
 49  
  *         Ma&icirc;tre</a>
 50  
  * @plexus.component role="org.codehaus.plexus.compiler.Compiler" role-hint="j2objc"
 51  
  */
 52  
 public class J2ObjCCompiler
 53  
     extends AbstractCompiler
 54  
 {
 55  
 
 56  
     private static final String X_BOOTCLASSPATH = "Xbootclasspath";
 57  
 
 58  
     /**
 59  
      * -J<flag> Pass Java <flag>, such as -Xmx1G, to the system runtime.
 60  
      */
 61  
     private static final String J_FLAG = "J";
 62  
 
 63  
     /**
 64  
      * --batch-translate-max=<n> The maximum number of source files that are
 65  
      * translated. together. Batching speeds up translation, but requires more
 66  
      * memory.
 67  
      */
 68  
     private static final String BATCH_SIZE = "batch-translate-max";
 69  
 
 70  
     /**
 71  
      * Put the arguments of j2objc who takes one dash inside an array, in order
 72  
      * the check the command line.
 73  
      */
 74  0
     private static final List<String> ONE_DASH_ARGS = Arrays.asList(
 75  
         new String[]{ "-pluginpath", "-pluginoptions", "-t", "-Xno-jsni-warnings", "-sourcepath", "-classpath", "-d",
 76  
             "-encoding", "-g", "-q", "-v", "-Werror", "-h", "-use-arc", "-use-reference-counting", "-x" } );
 77  
 
 78  
     /**
 79  
      * Put the command line arguments with 2 dashes inside an array, in order
 80  
      * the check the command line and build it.
 81  
      */
 82  0
     private static final List<String> TWO_DASH_ARGS = Arrays.asList(
 83  
         new String[]{ "--build-closure", "--dead-code-report", "--doc-comments", "--no-extract-unsequenced",
 84  
             "--generate-deprecated", "--mapping", "--no-class-methods", "--no-final-methods-functions",
 85  
             "--no-hide-private-members", "--no-package-directories", "--prefix", "--prefixes", "--preserve-full-paths",
 86  
             "--strip-gwt-incompatible", "--strip-reflection", "--segmented-headers", "--timing-info", "--quiet",
 87  
             "--verbose", "--help" } );
 88  
 
 89  
     public J2ObjCCompiler()
 90  
     {
 91  0
         super( CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, ".java", null, null );
 92  0
     }
 93  
 
 94  
     // ----------------------------------------------------------------------
 95  
     // Compiler Implementation
 96  
     // ----------------------------------------------------------------------
 97  
 
 98  
     public boolean canUpdateTarget( CompilerConfiguration configuration )
 99  
         throws CompilerException
 100  
     {
 101  0
         return false;
 102  
     }
 103  
 
 104  
     public CompilerResult performCompile( CompilerConfiguration config )
 105  
         throws CompilerException
 106  
     {
 107  0
         File destinationDir = new File( config.getOutputLocation() );
 108  0
         if ( !destinationDir.exists() )
 109  
         {
 110  0
             destinationDir.mkdirs();
 111  
         }
 112  
 
 113  0
         config.setSourceFiles( null );
 114  
 
 115  0
         String[] sourceFiles = J2ObjCCompiler.getSourceFiles( config );
 116  
 
 117  0
         if ( sourceFiles.length == 0 )
 118  
         {
 119  0
             return new CompilerResult().success( true );
 120  
         }
 121  
 
 122  0
         System.out.println(
 123  
             "Compiling " + sourceFiles.length + " " + "source file" + ( sourceFiles.length == 1 ? "" : "s" ) + " to "
 124  0
                 + destinationDir.getAbsolutePath() );
 125  
 
 126  0
         String[] args = buildCompilerArguments( config, sourceFiles );
 127  
 
 128  
         List<CompilerMessage> messages;
 129  
 
 130  0
         if ( config.isFork() )
 131  
         {
 132  0
             messages =
 133  0
                 compileOutOfProcess( config.getWorkingDirectory(), config.getBuildDirectory(), findExecutable( config ),
 134  
                                      args );
 135  
         }
 136  
         else
 137  
         {
 138  0
             throw new CompilerException( "This compiler doesn't support in-process compilation." );
 139  
         }
 140  
 
 141  0
         return new CompilerResult().compilerMessages( messages );
 142  
     }
 143  
 
 144  
     public String[] createCommandLine( CompilerConfiguration config )
 145  
         throws CompilerException
 146  
     {
 147  0
         return buildCompilerArguments( config, J2ObjCCompiler.getSourceFiles( config ) );
 148  
     }
 149  
 
 150  
     /**
 151  
      * Find the executable given in the configuration or use j2objc from the
 152  
      * PATH.
 153  
      *
 154  
      * @param config
 155  
      * @return the List<String> of args
 156  
      */
 157  
     private String findExecutable( CompilerConfiguration config )
 158  
     {
 159  0
         String executable = config.getExecutable();
 160  
 
 161  0
         if ( !StringUtils.isEmpty( executable ) )
 162  
         {
 163  0
             return executable;
 164  
         }
 165  
 
 166  0
         return "j2objc";
 167  
     }
 168  
 
 169  
     /**
 170  
      * Build the compiler arguments :
 171  
      * <li>the output location is used for -d of j2objc)
 172  
      * <li>the classpath entries are added to -classpath
 173  
      * <li>the sourcefiles are listed at the end of the command line
 174  
      * <li>the configuration can contain any of the arguments
 175  
      *
 176  
      * @param config
 177  
      * @param sourceFiles
 178  
      * @return The List<String> to give to the command line tool
 179  
      * @throws CompilerException
 180  
      */
 181  
     private String[] buildCompilerArguments( CompilerConfiguration config, String[] sourceFiles )
 182  
         throws CompilerException
 183  
     {
 184  
         /*
 185  
                  * j2objc --help Usage: j2objc <options> <source files>
 186  
                  */
 187  0
         List<String> args = new ArrayList<String>();
 188  0
         Map<String, String> compilerArguments = config.getCustomCompilerArgumentsAsMap();
 189  
 
 190  
         // Verbose
 191  0
         if ( config.isVerbose() )
 192  
         {
 193  0
             args.add( "-v" );
 194  
         }
 195  
 
 196  
         // Destination/output directory
 197  0
         args.add( "-d" );
 198  0
         args.add( config.getOutputLocation() );
 199  
 
 200  0
         if ( !config.getClasspathEntries().isEmpty() )
 201  
         {
 202  0
             List<String> classpath = new ArrayList<String>();
 203  0
             for ( String element : config.getClasspathEntries() )
 204  
             {
 205  0
                 File f = new File( element );
 206  0
                 classpath.add( f.getAbsolutePath() );
 207  
 
 208  0
                 classpath.add( element );
 209  0
             }
 210  0
             args.add( "-classpath" );
 211  0
             args.add( StringUtils.join( classpath.toArray(), File.pathSeparator ) );
 212  
         }
 213  
 
 214  0
         if ( config.isVerbose() )
 215  
         {
 216  0
             System.out.println( "Args: " );
 217  
         }
 218  
 
 219  0
         for ( String k : compilerArguments.keySet() )
 220  
         {
 221  0
             if ( config.isVerbose() )
 222  
             {
 223  0
                 System.out.println( k + "=" + compilerArguments.get( k ) );
 224  
             }
 225  0
             String v = compilerArguments.get( k );
 226  0
             if ( J_FLAG.equals( k ) )
 227  
             {
 228  0
                 args.add( J_FLAG + v );
 229  
             }
 230  0
             else if ( X_BOOTCLASSPATH.equals( k ) )
 231  
             {
 232  0
                 args.add( X_BOOTCLASSPATH + ":" + v );
 233  
             }
 234  0
             else if ( BATCH_SIZE.equals( k ) )
 235  
             {
 236  0
                 args.add( "-" + BATCH_SIZE + "=" + v );
 237  
             }
 238  
             else
 239  
             {
 240  0
                 if ( TWO_DASH_ARGS.contains( k ) )
 241  
                 {
 242  0
                     args.add( "-" + k );
 243  
                 }
 244  0
                 else if ( ONE_DASH_ARGS.contains( k ) )
 245  
                 {
 246  0
                     args.add( k );
 247  
                 }
 248  
                 else
 249  
                 {
 250  0
                     throw new IllegalArgumentException( "The argument " + k + " isnt't a flag recognized by J2ObjC." );
 251  
                 }
 252  0
                 if ( v != null )
 253  
                 {
 254  0
                     args.add( v );
 255  
                 }
 256  
             }
 257  0
         }
 258  
 
 259  0
         for ( String sourceFile : sourceFiles )
 260  
         {
 261  0
             args.add( sourceFile );
 262  
         }
 263  
 
 264  0
         return args.toArray( new String[args.size()] );
 265  
     }
 266  
 
 267  
     private List<CompilerMessage> compileOutOfProcess( File workingDirectory, File target, String executable,
 268  
                                                        String[] args )
 269  
         throws CompilerException
 270  
     {
 271  
 
 272  0
         Commandline cli = new Commandline();
 273  
 
 274  0
         cli.setWorkingDirectory( workingDirectory.getAbsolutePath() );
 275  
 
 276  0
         cli.setExecutable( executable );
 277  
 
 278  0
         cli.addArguments( args );
 279  
 
 280  0
         Writer stringWriter = new StringWriter();
 281  
 
 282  0
         StreamConsumer out = new WriterStreamConsumer( stringWriter );
 283  
 
 284  0
         StreamConsumer err = new WriterStreamConsumer( stringWriter );
 285  
 
 286  
         int returnCode;
 287  
 
 288  
         List<CompilerMessage> messages;
 289  
 
 290  
         try
 291  
         {
 292  0
             returnCode = CommandLineUtils.executeCommandLine( cli, out, err );
 293  
 
 294  0
             messages = parseCompilerOutput( new BufferedReader( new StringReader( stringWriter.toString() ) ) );
 295  
         }
 296  0
         catch ( CommandLineException e )
 297  
         {
 298  0
             throw new CompilerException( "Error while executing the external compiler.", e );
 299  
         }
 300  0
         catch ( IOException e )
 301  
         {
 302  0
             throw new CompilerException( "Error while executing the external compiler.", e );
 303  0
         }
 304  
 
 305  0
         if ( returnCode != 0 && messages.isEmpty() )
 306  
         {
 307  
             // TODO: exception?
 308  0
             messages.add( new CompilerMessage(
 309  0
                 "Failure executing the compiler, but could not parse the error:" + EOL + stringWriter.toString(),
 310  
                 Kind.ERROR ) );
 311  
         }
 312  
 
 313  0
         return messages;
 314  
     }
 315  
 
 316  
     public static List<CompilerMessage> parseCompilerOutput( BufferedReader bufferedReader )
 317  
         throws IOException
 318  
     {
 319  0
         List<CompilerMessage> messages = new ArrayList<CompilerMessage>();
 320  
 
 321  0
         String line = bufferedReader.readLine();
 322  
 
 323  0
         while ( line != null )
 324  
         {
 325  0
             CompilerMessage compilerError = DefaultJ2ObjCCompilerParser.parseLine( line );
 326  
 
 327  0
             if ( compilerError != null )
 328  
             {
 329  0
                 messages.add( compilerError );
 330  
             }
 331  
 
 332  0
             line = bufferedReader.readLine();
 333  0
         }
 334  
 
 335  0
         return messages;
 336  
     }
 337  
 
 338  
 }