/**
* Copyright (C) 2009 STMicroelectronics
*
* This file is part of "Mind Compiler" is free software: you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: mind@ow2.org
*
* Authors: Matthieu Leclercq
* Contributors: Julien Tous
*/
package org.ow2.mind;
import static org.ow2.mind.PathHelper.fullyQualifiedNameToPath;
import static org.ow2.mind.PathHelper.isRelative;
import static org.ow2.mind.compilation.DirectiveHelper.splitOptionString;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.fractal.adl.ADLException;
import org.objectweb.fractal.adl.Definition;
import org.objectweb.fractal.adl.Loader;
import org.objectweb.fractal.adl.error.Error;
import org.ow2.mind.adl.DefinitionCompiler;
import org.ow2.mind.adl.GraphCompiler;
import org.ow2.mind.adl.graph.ComponentGraph;
import org.ow2.mind.adl.graph.Instantiator;
import org.ow2.mind.compilation.CompilationCommand;
import org.ow2.mind.compilation.CompilationCommandExecutor;
import org.ow2.mind.compilation.CompilerCommand;
import org.ow2.mind.compilation.CompilerContextHelper;
import org.ow2.mind.error.ErrorCollection;
import org.ow2.mind.error.ErrorManager;
import org.ow2.mind.inject.GuiceModuleExtensionHelper;
import org.ow2.mind.io.BasicOutputFileLocator;
import org.ow2.mind.io.OutputFileLocator;
import org.ow2.mind.plugin.PluginLoaderModule;
import org.ow2.mind.plugin.PluginManager;
import org.testng.Assert;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class CompilerRunner {
public static final String DEFAULT_CFLAGS = "-g -Wall -Werror -Wredundant-decls -Wunreachable-code -Wstrict-prototypes -Wwrite-strings";
public static final String CFLAGS_PROPERTY = "mind.test.cflags";
public static final String COMPILER_PROPERTY = "mind.test.compiler";
public final ErrorManager errorManager;
public final Loader adlLoader;
public final Instantiator graphInstantiator;
public final OutputFileLocator outputFileLocator;
public final DefinitionCompiler definitionCompiler;
public final GraphCompiler graphCompiler;
public final CompilationCommandExecutor executor;
public final PluginManager pluginManager;
public final File buildDir;
public Map<Object, Object> context;
private final Map<Object, Object> initialContext;
public CompilerRunner() throws ADLException {
this(new HashMap<Object, Object>());
}
public CompilerRunner(final Map<Object, Object> initialContext)
throws ADLException {
this.initialContext = initialContext;
final Injector pluginManagerInjector = Guice
.createInjector(new PluginLoaderModule());
pluginManager = pluginManagerInjector.getInstance(PluginManager.class);
final Injector injector = Guice.createInjector(GuiceModuleExtensionHelper
.getModules(pluginManager, initialContext));
errorManager = injector.getInstance(ErrorManager.class);
adlLoader = injector.getInstance(Loader.class);
graphInstantiator = injector.getInstance(Instantiator.class);
graphCompiler = injector.getInstance(GraphCompiler.class);
outputFileLocator = injector.getInstance(OutputFileLocator.class);
definitionCompiler = injector.getInstance(DefinitionCompiler.class);
executor = injector.getInstance(CompilationCommandExecutor.class);
buildDir = new File("target/build");
// init context
initContext();
}
public void initContext() throws ADLException {
context = new HashMap<Object, Object>(initialContext);
if (!buildDir.exists()) {
buildDir.mkdirs();
}
context.put(BasicOutputFileLocator.OUTPUT_DIR_CONTEXT_KEY, buildDir);
final String cFlags = System.getProperty(CFLAGS_PROPERTY, DEFAULT_CFLAGS);
CompilerContextHelper.setCFlags(context, splitOptionString(cFlags));
final String compiler = System.getProperty(COMPILER_PROPERTY);
if (compiler != null) {
CompilerContextHelper.setCompilerCommand(context, compiler);
CompilerContextHelper.setAssemblerCommand(context, compiler);
CompilerContextHelper.setLinkerCommand(context, compiler);
}
}
public Definition load(final String adlName) throws ADLException {
errorManager.clear();
final Definition d = adlLoader.load(adlName, context);
final List<Error> errors = errorManager.getErrors();
if (!errors.isEmpty()) {
throw new ADLException(new ErrorCollection(errors));
}
return d;
}
public Collection<File> compileDefinition(final String adlName)
throws ADLException, InterruptedException {
final Definition d = load(adlName);
final Collection<CompilationCommand> c = definitionCompiler.visit(d,
context);
executor.exec(c, context);
final List<File> result = new ArrayList<File>();
for (final CompilationCommand command : c) {
if (command instanceof CompilerCommand)
result.addAll(command.getOutputFiles());
}
return result;
}
public File compile(final String adlName) throws ADLException,
InterruptedException {
return compile(adlName, null);
}
public File compile(final String adlName, final String executableName)
throws ADLException, InterruptedException {
String outputPath;
if (executableName != null) {
context.put("executable-name", executableName);
outputPath = executableName;
if (isRelative(outputPath)) {
outputPath = "/" + outputPath;
}
} else {
outputPath = fullyQualifiedNameToPath(adlName, null);
}
final File outputFile = outputFileLocator.getCExecutableOutputFile(
outputPath, context);
final Definition d = load(adlName);
final ComponentGraph componentGraph = graphInstantiator.instantiate(d,
context);
List<Error> errors = errorManager.getErrors();
if (!errors.isEmpty()) {
throw new ADLException(new ErrorCollection(errors));
}
final Collection<CompilationCommand> commands = graphCompiler.visit(
componentGraph, context);
final boolean execOK = executor.exec(commands, context);
errors = errorManager.getErrors();
if (!errors.isEmpty()) {
throw new ADLException(new ErrorCollection(errors));
}
assertTrue(
execOK,
"Execution of compilation commands returns false, but no error has been logged in error manager ");
return outputFile;
}
public int run(final File executable, final String... params)
throws Exception {
final Process p;
if (params != null && params.length > 0) {
final List<String> args = new ArrayList<String>(params.length + 1);
args.add(executable.getAbsolutePath());
for (final String param : params) {
args.add(param);
}
p = new ProcessBuilder(args).redirectErrorStream(true).start();
} else {
p = new ProcessBuilder(executable.getAbsolutePath()).redirectErrorStream(
true).start();
}
final Thread readerThread = new Thread() {
@Override
public void run() {
// output output and error stream on the logger.
final BufferedReader reader = new BufferedReader(new InputStreamReader(
p.getInputStream()));
try {
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
} catch (final IOException e) {
throw new java.lang.Error("Can't read error stream of process", e);
}
}
};
readerThread.start();
final int rValue = p.waitFor();
readerThread.join();
return rValue;
}
public int compileAndRun(final String adlName, final String executableName,
final String... params) throws Exception {
final File executable = compile(adlName, executableName);
assertNotNull(executable);
return run(executable, params);
}
public void compileRunAndCheck(final String adlName,
final String executableName, final String... params) throws Exception {
Assert.assertEquals(compileAndRun(adlName, executableName, params), 0,
"Unexpected result returned by test");
}
public void compileRunAndCheck(final String adlName) throws Exception {
compileRunAndCheck(adlName, null);
}
}