/*
* Copyright 2003-2011 the original author or authors.
* Copyright 2013 James Moger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.moxie.ant;
import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import groovy.lang.MissingMethodException;
import groovy.lang.Script;
import groovy.util.AntBuilder;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.util.FileUtils;
import org.codehaus.groovy.ant.AntProjectPropertiesDelegate;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.tools.ErrorReporter;
public class GroovyEngine {
private static final String PREFIX = "embedded_script_in_";
private static final String SUFFIX = "groovy_Ant_task";
protected void forkGroovy(MxGroovy task, final String txt) {
if ("".equals(txt.trim())) {
return;
}
try {
prepareGroovyScript(task, txt);
task.setClassname(task.useGroovyShell ? "groovy.lang.GroovyShell" : "org.codehaus.groovy.ant.Groovy");
task.executeFork();
} catch (Exception e) {
processError(task, e);
}
return;
}
/**
* Exec the statement.
*
* @param txt the groovy source to exec
* @param out not used?
*/
protected void execGroovy(MxGroovy task, final String txt, final PrintStream out) {
if ("".equals(txt.trim())) {
return;
}
ClassLoader savedLoader = null;
Thread thread = Thread.currentThread();
ClassLoader baseClassLoader = GroovyShell.class.getClassLoader();
if (task.contextClassLoader) {
savedLoader = thread.getContextClassLoader();
thread.setContextClassLoader(baseClassLoader);
}
GroovyClassLoader classLoader = new GroovyClassLoader(baseClassLoader);
if (task.getCommandLine().getClasspath() != null) {
for (String path : task.getCommandLine().getClasspath().list()) {
classLoader.addClasspath(path);
}
}
CompilerConfiguration configuration = new CompilerConfiguration();
if (task.stacktrace) {
configuration.setDebug(true);
}
GroovyShell groovy = new GroovyShell(classLoader, new Binding(), configuration);
try {
String scriptName = determineScriptName(task);
parseAndRunScript(task, groovy, scriptName, txt, null);
} finally {
groovy.resetLoadedClasses();
groovy.getClassLoader().clearCache();
if (task.contextClassLoader) {
thread.setContextClassLoader(savedLoader);
}
}
}
private void parseAndRunScript(MxGroovy task, GroovyShell shell, String scriptName, String txt, File scriptFile) {
try {
final Script script;
if (scriptFile != null) {
script = shell.parse(scriptFile);
} else {
script = shell.parse(txt, scriptName);
}
final Project project = task.getProject();
script.setProperty("ant", new AntBuilder(task));
script.setProperty("project", project);
script.setProperty("build", task.getBuild());
script.setProperty("properties", new AntProjectPropertiesDelegate(project));
script.setProperty("target", task.getOwningTarget());
script.setProperty("task", this);
script.setProperty("args", task.getCommandLine().getCommandline());
script.setProperty("pom", task.getBuild().getPom());
script.run();
}
catch (final MissingMethodException mme) {
// not a script, try running through run method but properties will not be available
if (scriptFile != null) {
try {
shell.run(scriptFile, task.getCommandLine().getCommandline());
} catch (IOException e) {
processError(task, e);
}
} else {
shell.run(txt, scriptName, task.getCommandLine().getCommandline());
}
}
catch (final CompilationFailedException e) {
processError(task, e);
} catch (IOException e) {
processError(task, e);
}
}
private void processError(MxGroovy task, Exception e) {
StringWriter writer = new StringWriter();
new ErrorReporter(e, false).write(new PrintWriter(writer));
String message = writer.toString();
throw new BuildException("Script Failed: " + message, e, task.getLocation());
}
private void prepareGroovyScript(MxGroovy task, String txt) throws IOException {
String[] args = task.getCommandLine().getCommandline();
// Temporary file - delete on exit, create (assured unique name).
File tempFile = FileUtils.getFileUtils().createTempFile(PREFIX, SUFFIX, null, true, true);
String[] commandline = new String[args.length + 1];
DefaultGroovyMethods.write(tempFile, txt);
commandline[0] = tempFile.getCanonicalPath();
System.arraycopy(args, 0, commandline, 1, args.length);
task.clearArgs();
for (String arg : commandline) {
Commandline.Argument argument = task.createArg();
argument.setValue(arg);
}
}
/**
* Try to build a script name for the script of the groovy task to have an
* helpful value in stack traces in case of exception.
*
* @return the name to use when compiling the script
*/
private String determineScriptName(MxGroovy task) {
if (task.srcFile != null) {
return task.srcFile.getAbsolutePath();
} else {
String name = PREFIX;
if (task.getLocation().getFileName().length() > 0)
name += task.getLocation().getFileName().replaceAll("[^\\w_\\.]", "_").replaceAll("[\\.]", "_dot_");
else
name += SUFFIX;
return name;
}
}
}