001 /* 002 $Id: CompilerConfiguration.java 3906 2006-07-19 00:11:46Z glaforge $ 003 004 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. 005 006 Redistribution and use of this software and associated documentation 007 ("Software"), with or without modification, are permitted provided 008 that the following conditions are met: 009 010 1. Redistributions of source code must retain copyright 011 statements and notices. Redistributions must also contain a 012 copy of this document. 013 014 2. Redistributions in binary form must reproduce the 015 above copyright notice, this list of conditions and the 016 following disclaimer in the documentation and/or other 017 materials provided with the distribution. 018 019 3. The name "groovy" must not be used to endorse or promote 020 products derived from this Software without prior written 021 permission of The Codehaus. For written permission, 022 please contact info@codehaus.org. 023 024 4. Products derived from this Software may not be called "groovy" 025 nor may "groovy" appear in their names without prior written 026 permission of The Codehaus. "groovy" is a registered 027 trademark of The Codehaus. 028 029 5. Due credit should be given to The Codehaus - 030 http://groovy.codehaus.org/ 031 032 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS 033 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 034 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 035 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 036 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 037 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 039 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 040 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 041 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 042 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 043 OF THE POSSIBILITY OF SUCH DAMAGE. 044 045 */ 046 047 package org.codehaus.groovy.control; 048 049 import org.codehaus.groovy.control.io.NullWriter; 050 import org.codehaus.groovy.control.messages.WarningMessage; 051 052 import java.io.File; 053 import java.io.PrintWriter; 054 import java.util.LinkedList; 055 import java.util.List; 056 import java.util.Properties; 057 import java.util.StringTokenizer; 058 059 060 /** 061 * Compilation control flags and coordination stuff. 062 * 063 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a> 064 * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a> 065 * @version $Id: CompilerConfiguration.java 3906 2006-07-19 00:11:46Z glaforge $ 066 */ 067 068 public class CompilerConfiguration { 069 public static final CompilerConfiguration DEFAULT = new CompilerConfiguration(); 070 071 /** Whether to use the JSR parser or not if no property is explicitly stated */ 072 protected static final boolean DEFAULT_JSR_FLAG = true; 073 074 private static boolean jsrGroovy; 075 076 /** 077 * See WarningMessage for levels 078 */ 079 private int warningLevel; 080 /** 081 * Encoding for source files 082 */ 083 private String sourceEncoding; 084 /** 085 * A PrintWriter for communicating with the user 086 */ 087 private PrintWriter output; 088 /** 089 * Directory into which to write classes 090 */ 091 private File targetDirectory; 092 /** 093 * Classpath for use during compilation 094 */ 095 private LinkedList classpath; 096 /** 097 * If true, the compiler should produce action information 098 */ 099 private boolean verbose; 100 /** 101 * If true, debugging code should be activated 102 */ 103 private boolean debug; 104 /** 105 * The number of non-fatal errors to allow before bailing 106 */ 107 private int tolerance; 108 /** 109 * Base class name for scripts (must derive from Script) 110 */ 111 private String scriptBaseClass; 112 /** 113 * should we use the New JSR Groovy parser or stay with the static one 114 */ 115 private boolean useNewGroovy = getDefaultJsrFlag(); 116 117 private ParserPluginFactory pluginFactory; 118 119 /** 120 * extension used to find a groovy file 121 */ 122 private String defaultScriptExtension = ".groovy"; 123 124 /** 125 * if set to true recompilation is enabled 126 */ 127 private boolean recompileGroovySource; 128 129 /** 130 * sets the minimum of time after a script can be recompiled. 131 */ 132 private int minimumRecompilationInterval; 133 134 /** 135 * Sets the Flags to defaults. 136 */ 137 public CompilerConfiguration() { 138 // 139 // Set in safe defaults 140 141 setWarningLevel(WarningMessage.LIKELY_ERRORS); 142 setSourceEncoding("US-ASCII"); 143 setOutput(null); 144 setTargetDirectory((File) null); 145 setClasspath(""); 146 setVerbose(false); 147 setDebug(false); 148 setTolerance(10); 149 setScriptBaseClass(null); 150 setRecompileGroovySource(false); 151 setMinimumRecompilationInterval(100); 152 153 154 // 155 // Try for better defaults, ignore errors. 156 157 try { 158 setSourceEncoding(System.getProperty("file.encoding", "US-ASCII")); 159 } 160 catch (Exception e) { 161 } 162 try { 163 setOutput(new PrintWriter(System.err)); 164 } 165 catch (Exception e) { 166 } 167 /*try { 168 setClasspath(System.getProperty("java.class.path")); 169 } 170 catch (Exception e) { 171 }*/ 172 173 try { 174 String target = System.getProperty("groovy.target.directory"); 175 if (target != null) { 176 setTargetDirectory(target); 177 } 178 } 179 catch (Exception e) { 180 } 181 } 182 183 184 /** 185 * Sets the Flags to the specified configuration, with defaults 186 * for those not supplied. 187 */ 188 189 public CompilerConfiguration(Properties configuration) throws ConfigurationException { 190 this(); 191 192 String text = null; 193 int numeric = 0; 194 195 196 // 197 // Warning level 198 199 numeric = getWarningLevel(); 200 try { 201 text = configuration.getProperty("groovy.warnings", "likely errors"); 202 numeric = Integer.parseInt(text); 203 } 204 catch (NumberFormatException e) { 205 if (text.equals("none")) { 206 numeric = WarningMessage.NONE; 207 } 208 else if (text.startsWith("likely")) { 209 numeric = WarningMessage.LIKELY_ERRORS; 210 } 211 else if (text.startsWith("possible")) { 212 numeric = WarningMessage.POSSIBLE_ERRORS; 213 } 214 else if (text.startsWith("paranoia")) { 215 numeric = WarningMessage.PARANOIA; 216 } 217 else { 218 throw new ConfigurationException("unrecogized groovy.warnings: " + text); 219 } 220 } 221 222 setWarningLevel(numeric); 223 224 225 // 226 // Source file encoding 227 228 text = configuration.getProperty("groovy.source.encoding"); 229 if (text != null) { 230 setSourceEncoding(text); 231 } 232 233 234 // 235 // Target directory for classes 236 237 text = configuration.getProperty("groovy.target.directory"); 238 if (text != null) { 239 setTargetDirectory(text); 240 } 241 242 243 // 244 // Classpath 245 246 text = configuration.getProperty("groovy.classpath"); 247 if (text != null) { 248 setClasspath(text); 249 } 250 251 252 // 253 // Verbosity 254 255 text = configuration.getProperty("groovy.output.verbose"); 256 if (text != null && text.equals("true")) { 257 setVerbose(true); 258 } 259 260 261 // 262 // Debugging 263 264 text = configuration.getProperty("groovy.output.debug"); 265 if (text != null && text.equals("true")) { 266 setDebug(true); 267 } 268 269 270 // 271 // Tolerance 272 273 numeric = 10; 274 275 try { 276 text = configuration.getProperty("groovy.errors.tolerance", "10"); 277 numeric = Integer.parseInt(text); 278 } 279 catch (NumberFormatException e) { 280 throw new ConfigurationException(e); 281 } 282 283 setTolerance(numeric); 284 285 286 // 287 // Script Base Class 288 289 text = configuration.getProperty("groovy.script.base"); 290 setScriptBaseClass(text); 291 292 text = configuration.getProperty("groovy.jsr"); 293 if (text != null) { 294 setUseNewGroovy(text.equalsIgnoreCase("true")); 295 } 296 297 298 // 299 // recompilation options 300 // 301 text = configuration.getProperty("groovy.recompile"); 302 if (text != null) { 303 setRecompileGroovySource(text.equalsIgnoreCase("true")); 304 } 305 306 numeric = 100; 307 try { 308 text = configuration.getProperty("groovy.recompile.minimumIntervall", ""+numeric); 309 numeric = Integer.parseInt(text); 310 } 311 catch (NumberFormatException e) { 312 throw new ConfigurationException(e); 313 } 314 setMinimumRecompilationInterval(numeric); 315 316 317 } 318 319 320 /** 321 * Gets the currently configured warning level. See WarningMessage 322 * for level details. 323 */ 324 public int getWarningLevel() { 325 return this.warningLevel; 326 } 327 328 329 /** 330 * Sets the warning level. See WarningMessage for level details. 331 */ 332 public void setWarningLevel(int level) { 333 if (level < WarningMessage.NONE || level > WarningMessage.PARANOIA) { 334 this.warningLevel = WarningMessage.LIKELY_ERRORS; 335 } 336 else { 337 this.warningLevel = level; 338 } 339 } 340 341 342 /** 343 * Gets the currently configured source file encoding. 344 */ 345 public String getSourceEncoding() { 346 return this.sourceEncoding; 347 } 348 349 350 /** 351 * Sets the encoding to be used when reading source files. 352 */ 353 public void setSourceEncoding(String encoding) { 354 this.sourceEncoding = encoding; 355 } 356 357 358 /** 359 * Gets the currently configured output writer. 360 */ 361 public PrintWriter getOutput() { 362 return this.output; 363 } 364 365 366 /** 367 * Sets the output writer. 368 */ 369 public void setOutput(PrintWriter output) { 370 if (this.output == null) { 371 this.output = new PrintWriter(NullWriter.DEFAULT); 372 } 373 else { 374 this.output = output; 375 } 376 } 377 378 379 /** 380 * Gets the target directory for writing classes. 381 */ 382 public File getTargetDirectory() { 383 return this.targetDirectory; 384 } 385 386 387 /** 388 * Sets the target directory. 389 */ 390 public void setTargetDirectory(String directory) { 391 if (directory != null && directory.length() > 0) { 392 this.targetDirectory = new File(directory); 393 } 394 else { 395 this.targetDirectory = null; 396 } 397 } 398 399 400 /** 401 * Sets the target directory. 402 */ 403 public void setTargetDirectory(File directory) { 404 this.targetDirectory = directory; 405 } 406 407 408 /** 409 * Gets the classpath. 410 */ 411 public List getClasspath() { 412 return this.classpath; 413 } 414 415 416 /** 417 * Sets the classpath. 418 */ 419 public void setClasspath(String classpath) { 420 this.classpath = new LinkedList(); 421 422 StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator); 423 while (tokenizer.hasMoreTokens()) { 424 this.classpath.add(tokenizer.nextToken()); 425 } 426 } 427 428 429 /** 430 * Returns true if verbose operation has been requested. 431 */ 432 public boolean getVerbose() { 433 return this.verbose; 434 } 435 436 437 /** 438 * Turns verbose operation on or off. 439 */ 440 public void setVerbose(boolean verbose) { 441 this.verbose = verbose; 442 } 443 444 445 /** 446 * Returns true if debugging operation has been requested. 447 */ 448 public boolean getDebug() { 449 return this.debug; 450 } 451 452 453 /** 454 * Turns debugging operation on or off. 455 */ 456 public void setDebug(boolean debug) { 457 this.debug = debug; 458 } 459 460 461 /** 462 * Returns the requested error tolerance. 463 */ 464 public int getTolerance() { 465 return this.tolerance; 466 } 467 468 469 /** 470 * Sets the error tolerance, which is the number of 471 * non-fatal errors (per unit) that should be tolerated before 472 * compilation is aborted. 473 */ 474 public void setTolerance(int tolerance) { 475 this.tolerance = tolerance; 476 } 477 478 479 /** 480 * Gets the name of the base class for scripts. It must be a subclass 481 * of Script. 482 */ 483 public String getScriptBaseClass() { 484 return this.scriptBaseClass; 485 } 486 487 488 /** 489 * Sets the name of the base class for scripts. It must be a subclass 490 * of Script. 491 */ 492 public void setScriptBaseClass(String scriptBaseClass) { 493 this.scriptBaseClass = scriptBaseClass; 494 } 495 496 /** 497 * Returns true if the new groovy (JSR) parser is enabled 498 */ 499 public boolean isUseNewGroovy() { 500 return useNewGroovy; 501 } 502 503 public void setUseNewGroovy(boolean useNewGroovy) { 504 this.useNewGroovy = useNewGroovy; 505 } 506 507 public ParserPluginFactory getPluginFactory() { 508 if (pluginFactory == null) { 509 pluginFactory = ParserPluginFactory.newInstance(isUseNewGroovy()); 510 } 511 return pluginFactory; 512 } 513 514 public void setPluginFactory(ParserPluginFactory pluginFactory) { 515 this.pluginFactory = pluginFactory; 516 } 517 518 /** 519 * Returns true if we are the JSR compatible Groovy language 520 */ 521 public static boolean isJsrGroovy() { 522 return jsrGroovy; 523 } 524 525 /** 526 * Should only be called by the JSR parser 527 */ 528 public static void setJsrGroovy(boolean value) { 529 jsrGroovy = value; 530 } 531 532 protected static boolean getDefaultJsrFlag() { 533 // TODO a temporary hack while we have 2 parsers 534 String property = null; 535 try { 536 property = System.getProperty("groovy.jsr"); 537 } 538 catch (Throwable e) { 539 // ignore security warnings 540 } 541 if (property != null) { 542 return "true".equalsIgnoreCase(property); 543 } 544 return DEFAULT_JSR_FLAG; 545 } 546 547 548 public String getDefaultScriptExtension() { 549 return defaultScriptExtension; 550 } 551 552 553 public void setDefaultScriptExtension(String defaultScriptExtension) { 554 this.defaultScriptExtension = defaultScriptExtension; 555 } 556 557 public void setRecompileGroovySource(boolean recompile) { 558 recompileGroovySource = recompile; 559 } 560 561 public boolean getRecompileGroovySource(){ 562 return recompileGroovySource; 563 } 564 565 public void setMinimumRecompilationInterval(int time) { 566 minimumRecompilationInterval = Math.max(0,time); 567 } 568 569 public int getMinimumRecompilationInterval() { 570 return minimumRecompilationInterval; 571 } 572 573 }