2 * Copyright 2000-2007 JetBrains s.r.o.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 package org
.jetbrains
.groovy
.compiler
.rt
;
18 import groovy
.lang
.GroovyClassLoader
;
19 import org
.codehaus
.groovy
.ast
.ClassNode
;
20 import org
.codehaus
.groovy
.classgen
.GeneratorContext
;
21 import org
.codehaus
.groovy
.control
.*;
22 import org
.codehaus
.groovy
.control
.messages
.WarningMessage
;
23 import org
.codehaus
.groovy
.tools
.javac
.JavaAwareResolveVisitor
;
24 import org
.codehaus
.groovy
.tools
.javac
.JavaStubGenerator
;
27 import java
.net
.MalformedURLException
;
29 import java
.security
.AccessController
;
30 import java
.security
.PrivilegedAction
;
34 * @author: Dmitry.Krasilschikov
36 * @noinspection UseOfSystemOutOrSystemErr,CallToPrintStackTrace
39 public class GroovycRunner
{
41 public static final String PATCHERS
= "patchers";
42 public static final String ENCODING
= "encoding";
43 public static final String OUTPUTPATH
= "outputpath";
44 public static final String FINAL_OUTPUTPATH
= "final_outputpath";
45 public static final String END
= "end";
47 public static final String SRC_FILE
= "src_file";
48 public static final String COMPILED_START
= "%%c";
50 public static final String COMPILED_END
= "/%c";
51 public static final String TO_RECOMPILE_START
= "%%rc";
53 public static final String TO_RECOMPILE_END
= "/%rc";
54 public static final String MESSAGES_START
= "%%m";
56 public static final String MESSAGES_END
= "/%m";
57 public static final String SEPARATOR
= "#%%#%%%#%%%%%%%%%#";
59 //public static final Controller ourController = initController();
60 public static final String PRESENTABLE_MESSAGE
= "@#$%@# Presentable:";
61 public static final String CLEAR_PRESENTABLE
= "$@#$%^ CLEAR_PRESENTABLE";
63 private GroovycRunner() {
67 private static Controller initController() {
68 if (!"true".equals(System.getProperty("profile.groovy.compiler"))) {
73 return new Controller();
75 catch (Exception ex) {
83 public static void main(String
[] args
) {
85 if (ourController != null) {
87 ourController.startCPUProfiling(ProfilingModes.CPU_SAMPLING, null);
95 if (args
.length
!= 2) {
96 System
.err
.println("There is no arguments for groovy compiler");
100 final boolean forStubs
= "stubs".equals(args
[0]);
101 final File argsFile
= new File(args
[1]);
103 if (!argsFile
.exists()) {
104 System
.err
.println("Arguments file for groovy compiler not found");
109 final CompilerConfiguration compilerConfiguration
= new CompilerConfiguration();
110 compilerConfiguration
.setOutput(new PrintWriter(System
.err
));
111 compilerConfiguration
.setWarningLevel(WarningMessage
.PARANOIA
);
113 final List compilerMessages
= new ArrayList();
114 final List patchers
= new ArrayList();
115 final List srcFiles
= new ArrayList();
116 final Map class2File
= new HashMap();
118 final String
[] finalOutput
= new String
[1];
119 fillFromArgsFile(argsFile
, compilerConfiguration
, patchers
, compilerMessages
, srcFiles
, class2File
, finalOutput
);
120 if (srcFiles
.isEmpty()) return;
122 System
.out
.println(PRESENTABLE_MESSAGE
+ "Groovy compiler: loading sources...");
123 final CompilationUnit unit
= createCompilationUnit(forStubs
, compilerConfiguration
, finalOutput
[0]);
124 addSources(forStubs
, srcFiles
, unit
);
125 runPatchers(patchers
, compilerMessages
, class2File
, unit
);
127 System
.out
.println(PRESENTABLE_MESSAGE
+ "Groovyc: compiling...");
128 final List compiledFiles
= GroovyCompilerWrapper
.compile(compilerMessages
, forStubs
, unit
);
129 System
.out
.println(CLEAR_PRESENTABLE
);
131 System
.out
.println();
132 reportCompiledItems(compiledFiles
);
134 System
.out
.println();
135 if (compiledFiles
.isEmpty()) {
136 reportNotCompiledItems(srcFiles
);
140 for (int i
= 0; i
< compilerMessages
.size(); i
++) {
141 CompilerMessage message
= (CompilerMessage
)compilerMessages
.get(i
);
143 if (message
.getCategory() == CompilerMessage
.ERROR
) {
144 if (errorCount
> 100) {
150 printMessage(message
);
153 catch (Throwable e
) {
158 if (ourController != null) {
160 ourController.captureSnapshot(ProfilingModes.SNAPSHOT_WITHOUT_HEAP);
161 ourController.stopCPUProfiling();
163 catch (Exception e) {
171 private static String
fillFromArgsFile(File argsFile
, CompilerConfiguration compilerConfiguration
, List patchers
, List compilerMessages
,
172 List srcFiles
, Map class2File
, String
[] finalOutput
) {
173 String moduleClasspath
= null;
175 BufferedReader reader
= null;
176 FileInputStream stream
;
179 stream
= new FileInputStream(argsFile
);
180 reader
= new BufferedReader(new InputStreamReader(stream
));
184 while ((line
= reader
.readLine()) != null) {
185 if (!SRC_FILE
.equals(line
)) {
189 final File file
= new File(reader
.readLine());
191 while (!END
.equals(line
= reader
.readLine())) {
192 class2File
.put(line
, file
);
197 while (line
!= null) {
198 if (line
.startsWith(PATCHERS
)) {
200 while (!END
.equals(s
= reader
.readLine())) {
202 final CompilationUnitPatcher patcher
= (CompilationUnitPatcher
)Class
.forName(s
).newInstance();
203 patchers
.add(patcher
);
205 catch (InstantiationException e
) {
206 addExceptionInfo(compilerMessages
, e
, "Couldn't instantiate " + s
);
208 catch (IllegalAccessException e
) {
209 addExceptionInfo(compilerMessages
, e
, "Couldn't instantiate " + s
);
211 catch (ClassNotFoundException e
) {
212 addExceptionInfo(compilerMessages
, e
, "Couldn't instantiate " + s
);
216 else if (line
.startsWith(ENCODING
)) {
217 compilerConfiguration
.setSourceEncoding(reader
.readLine());
219 else if (line
.startsWith(OUTPUTPATH
)) {
220 compilerConfiguration
.setTargetDirectory(reader
.readLine());
222 else if (line
.startsWith(FINAL_OUTPUTPATH
)) {
223 finalOutput
[0] = reader
.readLine();
226 line
= reader
.readLine();
230 catch (FileNotFoundException e
) {
233 catch (IOException e
) {
240 catch (IOException e
) {
247 return moduleClasspath
;
250 private static void addSources(boolean forStubs
, List srcFiles
, final CompilationUnit unit
) {
251 for (int i
= 0; i
< srcFiles
.size(); i
++) {
252 final File file
= (File
)srcFiles
.get(i
);
253 if (forStubs
&& file
.getName().endsWith(".java")) {
254 // unit.addSources(new File[]{file});
258 unit
.addSource(new SourceUnit(file
, unit
.getConfiguration(), unit
.getClassLoader(), unit
.getErrorCollector()) {
259 public void parse() throws CompilationFailedException
{
260 System
.out
.println(PRESENTABLE_MESSAGE
+ "Parsing " + file
.getName() + "...");
262 System
.out
.println(CLEAR_PRESENTABLE
);
268 private static void runPatchers(List patchers
, List compilerMessages
, Map class2File
, CompilationUnit unit
) {
269 if (!patchers
.isEmpty()) {
270 final PsiAwareResourceLoader loader
= new PsiAwareResourceLoader(class2File
);
271 for (int i
= 0; i
< patchers
.size(); i
++) {
272 final CompilationUnitPatcher patcher
= (CompilationUnitPatcher
)patchers
.get(i
);
274 patcher
.patchCompilationUnit(unit
, loader
);
276 catch (LinkageError e
) {
277 addExceptionInfo(compilerMessages
, e
, "Couldn't run " + patcher
.getClass().getName());
283 private static void reportNotCompiledItems(Collection toRecompile
) {
284 for (Iterator iterator
= toRecompile
.iterator(); iterator
.hasNext();) {
285 File file
= (File
)iterator
.next();
286 System
.out
.print(TO_RECOMPILE_START
);
287 System
.out
.print(file
.getAbsolutePath());
288 System
.out
.print(TO_RECOMPILE_END
);
289 System
.out
.println();
293 private static void reportCompiledItems(List compiledFiles
) {
294 for (int i
= 0; i
< compiledFiles
.size(); i
++) {
298 * output root directory
300 GroovyCompilerWrapper
.OutputItem compiledOutputItem
= (GroovyCompilerWrapper
.OutputItem
)compiledFiles
.get(i
);
301 System
.out
.print(COMPILED_START
);
302 System
.out
.print(compiledOutputItem
.getOutputPath());
303 System
.out
.print(SEPARATOR
);
304 System
.out
.print(compiledOutputItem
.getSourceFile());
305 System
.out
.print(SEPARATOR
);
306 System
.out
.print(compiledOutputItem
.getOutputRootDirectory());
307 System
.out
.print(COMPILED_END
);
308 System
.out
.println();
312 private static void printMessage(CompilerMessage message
) {
313 System
.out
.print(MESSAGES_START
);
314 System
.out
.print(message
.getCategory());
315 System
.out
.print(SEPARATOR
);
316 System
.out
.print(message
.getMessage());
317 System
.out
.print(SEPARATOR
);
318 System
.out
.print(message
.getUrl());
319 System
.out
.print(SEPARATOR
);
320 System
.out
.print(message
.getLineNum());
321 System
.out
.print(SEPARATOR
);
322 System
.out
.print(message
.getColumnNum());
323 System
.out
.print(SEPARATOR
);
324 System
.out
.print(MESSAGES_END
);
325 System
.out
.println();
328 private static void addExceptionInfo(List compilerMessages
, Throwable e
, String message
) {
329 final StringWriter writer
= new StringWriter();
330 e
.printStackTrace(new PrintWriter(writer
));
331 compilerMessages
.add(new CompilerMessage(CompilerMessage
.WARNING
, message
+ ":\n" + writer
, "<exception>", -1, -1));
334 private static CompilationUnit
createCompilationUnit(final boolean forStubs
, final CompilerConfiguration config
, final String finalOutput
) {
335 config
.setClasspath("");
337 final GroovyClassLoader classLoader
= buildClassLoaderFor(config
);
339 final GroovyClassLoader transformLoader
= new GroovyClassLoader(classLoader
) {
340 public Enumeration
getResources(String name
) throws IOException
{
341 if (name
.endsWith("org.codehaus.groovy.transform.ASTTransformation")) {
342 final Enumeration resources
= super.getResources(name
);
343 final ArrayList list
= Collections
.list(resources
);
344 for (Iterator iterator
= list
.iterator(); iterator
.hasNext();) {
345 final String file
= ((URL
)iterator
.next()).getFile();
346 if (file
.contains(finalOutput
)) {
350 return Collections
.enumeration(list
);
352 return super.getResources(name
);
355 CompilationUnit unit
;
357 unit
= new CompilationUnit(config
, null, classLoader
, transformLoader
) {
359 public void gotoPhase(int phase
) throws CompilationFailedException
{
360 super.gotoPhase(phase
);
361 if (phase
<= Phases
.ALL
) {
362 System
.out
.println(PRESENTABLE_MESSAGE
+ (forStubs ?
"Groovy stub generator: " : "Groovy compiler: ") + getPhaseDescription());
367 catch (NoSuchMethodError e
) {
369 unit
= new CompilationUnit(config
, null, classLoader
) {
371 public void gotoPhase(int phase
) throws CompilationFailedException
{
372 super.gotoPhase(phase
);
373 if (phase
<= Phases
.ALL
) {
374 System
.out
.println(PRESENTABLE_MESSAGE
+ (forStubs ?
"Groovy stub generator: " : "Groovy compiler: ") + getPhaseDescription());
381 addStubGeneration(config
, unit
);
383 catch (LinkageError e
) {
384 //older groovy distributions, just don't generate stubs
390 private static void addStubGeneration(CompilerConfiguration config
, final CompilationUnit unit
) {
391 //todo reuse JavaStubCompilationUnit in groovy 1.7
392 boolean useJava5
= config
.getTargetBytecode().equals(CompilerConfiguration
.POST_JDK5
);
393 final JavaStubGenerator stubGenerator
= new JavaStubGenerator(config
.getTargetDirectory(), false, useJava5
);
395 //but JavaStubCompilationUnit doesn't have this...
396 unit
.addPhaseOperation(new CompilationUnit
.PrimaryClassNodeOperation() {
397 public void call(SourceUnit source
, GeneratorContext context
, ClassNode node
) throws CompilationFailedException
{
398 new JavaAwareResolveVisitor(unit
).startResolving(node
, source
);
400 }, Phases
.CONVERSION
);
402 unit
.addPhaseOperation(new CompilationUnit
.PrimaryClassNodeOperation() {
403 public void call(final SourceUnit source
, final GeneratorContext context
, final ClassNode node
) throws CompilationFailedException
{
404 final String name
= node
.getNameWithoutPackage();
405 if ("package-info".equals(name
)) {
409 System
.out
.println(PRESENTABLE_MESSAGE
+ "Generating stub for " + name
);
411 stubGenerator
.generateClass(node
);
413 catch (FileNotFoundException e
) {
414 source
.addException(e
);
417 },Phases
.CONVERSION
);
420 static GroovyClassLoader
buildClassLoaderFor(final CompilerConfiguration compilerConfiguration
) {
421 return (GroovyClassLoader
) AccessController
.doPrivileged(new PrivilegedAction() {
422 public Object
run() {
423 return new GroovyClassLoader(getClass().getClassLoader(), compilerConfiguration
) {
424 public Class
loadClass(String name
, boolean lookupScriptFiles
, boolean preferClassOverScript
)
425 throws ClassNotFoundException
, CompilationFailedException
{
427 return super.loadClass(name
, lookupScriptFiles
, preferClassOverScript
);
429 catch (NoClassDefFoundError e
) {
430 final String ncdfe
= e
.getMessage();
432 throw new RuntimeException("Groovyc error: " + ncdfe
+ " class not found while resolving class " + name
+ "; try compiling " + ncdfe
+ " explicitly", e
);
434 catch (LinkageError e
) {
435 throw new RuntimeException("Problem loading class " + name
, e
);