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 && !line
.equals(OUTPUTPATH
)) {
185 if (SRC_FILE
.equals(line
)) {
186 final File file
= new File(reader
.readLine());
189 while (!END
.equals(s
= reader
.readLine())) {
190 class2File
.put(s
, file
);
195 while (line
!= null) {
196 if (line
.startsWith(PATCHERS
)) {
198 while (!END
.equals(s
= reader
.readLine())) {
200 final CompilationUnitPatcher patcher
= (CompilationUnitPatcher
)Class
.forName(s
).newInstance();
201 patchers
.add(patcher
);
203 catch (InstantiationException e
) {
204 addExceptionInfo(compilerMessages
, e
, "Couldn't instantiate " + s
);
206 catch (IllegalAccessException e
) {
207 addExceptionInfo(compilerMessages
, e
, "Couldn't instantiate " + s
);
209 catch (ClassNotFoundException e
) {
210 addExceptionInfo(compilerMessages
, e
, "Couldn't instantiate " + s
);
214 else if (line
.startsWith(ENCODING
)) {
215 compilerConfiguration
.setSourceEncoding(reader
.readLine());
217 else if (line
.startsWith(OUTPUTPATH
)) {
218 compilerConfiguration
.setTargetDirectory(reader
.readLine());
220 else if (line
.startsWith(FINAL_OUTPUTPATH
)) {
221 finalOutput
[0] = reader
.readLine();
224 line
= reader
.readLine();
228 catch (FileNotFoundException e
) {
231 catch (IOException e
) {
238 catch (IOException e
) {
245 return moduleClasspath
;
248 private static void addSources(boolean forStubs
, List srcFiles
, final CompilationUnit unit
) {
249 for (int i
= 0; i
< srcFiles
.size(); i
++) {
250 final File file
= (File
)srcFiles
.get(i
);
251 if (forStubs
&& file
.getName().endsWith(".java")) {
252 // unit.addSources(new File[]{file});
256 unit
.addSource(new SourceUnit(file
, unit
.getConfiguration(), unit
.getClassLoader(), unit
.getErrorCollector()) {
257 public void parse() throws CompilationFailedException
{
258 System
.out
.println(PRESENTABLE_MESSAGE
+ "Parsing " + file
.getName() + "...");
260 System
.out
.println(CLEAR_PRESENTABLE
);
266 private static void runPatchers(List patchers
, List compilerMessages
, Map class2File
, CompilationUnit unit
) {
267 if (!patchers
.isEmpty()) {
268 final PsiAwareResourceLoader loader
= new PsiAwareResourceLoader(class2File
);
269 for (int i
= 0; i
< patchers
.size(); i
++) {
270 final CompilationUnitPatcher patcher
= (CompilationUnitPatcher
)patchers
.get(i
);
272 patcher
.patchCompilationUnit(unit
, loader
);
274 catch (LinkageError e
) {
275 addExceptionInfo(compilerMessages
, e
, "Couldn't run " + patcher
.getClass().getName());
281 private static void reportNotCompiledItems(Collection toRecompile
) {
282 for (Iterator iterator
= toRecompile
.iterator(); iterator
.hasNext();) {
283 File file
= (File
)iterator
.next();
284 System
.out
.print(TO_RECOMPILE_START
);
285 System
.out
.print(file
.getAbsolutePath());
286 System
.out
.print(TO_RECOMPILE_END
);
287 System
.out
.println();
291 private static void reportCompiledItems(List compiledFiles
) {
292 for (int i
= 0; i
< compiledFiles
.size(); i
++) {
296 * output root directory
298 GroovyCompilerWrapper
.OutputItem compiledOutputItem
= (GroovyCompilerWrapper
.OutputItem
)compiledFiles
.get(i
);
299 System
.out
.print(COMPILED_START
);
300 System
.out
.print(compiledOutputItem
.getOutputPath());
301 System
.out
.print(SEPARATOR
);
302 System
.out
.print(compiledOutputItem
.getSourceFile());
303 System
.out
.print(SEPARATOR
);
304 System
.out
.print(compiledOutputItem
.getOutputRootDirectory());
305 System
.out
.print(COMPILED_END
);
306 System
.out
.println();
310 private static void printMessage(CompilerMessage message
) {
311 System
.out
.print(MESSAGES_START
);
312 System
.out
.print(message
.getCategory());
313 System
.out
.print(SEPARATOR
);
314 System
.out
.print(message
.getMessage());
315 System
.out
.print(SEPARATOR
);
316 System
.out
.print(message
.getUrl());
317 System
.out
.print(SEPARATOR
);
318 System
.out
.print(message
.getLineNum());
319 System
.out
.print(SEPARATOR
);
320 System
.out
.print(message
.getColumnNum());
321 System
.out
.print(SEPARATOR
);
322 System
.out
.print(MESSAGES_END
);
323 System
.out
.println();
326 private static void addExceptionInfo(List compilerMessages
, Throwable e
, String message
) {
327 final StringWriter writer
= new StringWriter();
328 e
.printStackTrace(new PrintWriter(writer
));
329 compilerMessages
.add(new CompilerMessage(CompilerMessage
.WARNING
, message
+ ":\n" + writer
, "<exception>", -1, -1));
332 private static CompilationUnit
createCompilationUnit(final boolean forStubs
, final CompilerConfiguration config
, final String finalOutput
) {
333 config
.setClasspathList(Collections
.EMPTY_LIST
);
335 final GroovyClassLoader classLoader
= buildClassLoaderFor(config
);
337 final GroovyClassLoader transformLoader
= new GroovyClassLoader(classLoader
) {
338 public Enumeration
getResources(String name
) throws IOException
{
340 //return Collections.enumeration(Collections.EMPTY_LIST);
343 if (name
.endsWith("org.codehaus.groovy.transform.ASTTransformation")) {
344 final Enumeration resources
= super.getResources(name
);
345 final ArrayList list
= Collections
.list(resources
);
346 for (Iterator iterator
= list
.iterator(); iterator
.hasNext();) {
347 final String file
= ((URL
)iterator
.next()).getFile();
348 if (file
.contains(finalOutput
)) {
352 return Collections
.enumeration(list
);
354 return super.getResources(name
);
357 final CompilationUnit 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 //todo reuse JavaStubCompilationUnit in groovy 1.7
368 boolean useJava5
= config
.getTargetBytecode().equals(CompilerConfiguration
.POST_JDK5
);
369 final JavaStubGenerator stubGenerator
= new JavaStubGenerator(config
.getTargetDirectory(), false, useJava5
);
371 //but JavaStubCompilationUnit doesn't have this...
372 unit
.addPhaseOperation(new CompilationUnit
.PrimaryClassNodeOperation() {
373 public void call(SourceUnit source
, GeneratorContext context
, ClassNode node
) throws CompilationFailedException
{
374 new JavaAwareResolveVisitor(unit
).startResolving(node
, source
);
376 },Phases
.CONVERSION
);
378 unit
.addPhaseOperation(new CompilationUnit
.PrimaryClassNodeOperation() {
379 public void call(final SourceUnit source
, final GeneratorContext context
, final ClassNode node
) throws CompilationFailedException
{
380 final String name
= node
.getNameWithoutPackage();
381 if ("package-info".equals(name
)) {
385 System
.out
.println(PRESENTABLE_MESSAGE
+ "Generating stub for " + name
);
387 stubGenerator
.generateClass(node
);
389 catch (FileNotFoundException e
) {
390 source
.addException(e
);
393 },Phases
.CONVERSION
);
398 static GroovyClassLoader
buildClassLoaderFor(final CompilerConfiguration compilerConfiguration
) {
399 return (GroovyClassLoader
) AccessController
.doPrivileged(new PrivilegedAction() {
400 public Object
run() {
401 return new GroovyClassLoader(getClass().getClassLoader(), compilerConfiguration
) {
402 public Class
loadClass(String name
, boolean lookupScriptFiles
, boolean preferClassOverScript
)
403 throws ClassNotFoundException
, CompilationFailedException
{
405 return super.loadClass(name
, lookupScriptFiles
, preferClassOverScript
);
407 catch (NoClassDefFoundError e
) {
408 final String ncdfe
= e
.getMessage();
410 throw new RuntimeException("Groovyc error: " + ncdfe
+ " class not found while resolving class " + name
+ "; try compiling " + ncdfe
+ " explicitly", e
);
412 catch (LinkageError e
) {
413 throw new RuntimeException("Problem loading class " + name
, e
);