diff --git a/plugins/org.eclipse.acceleo.aql.launcher/src/org/eclipse/acceleo/aql/launcher/AcceleoLauncher.java b/plugins/org.eclipse.acceleo.aql.launcher/src/org/eclipse/acceleo/aql/launcher/AcceleoLauncher.java index e9beef79f..584649597 100644 --- a/plugins/org.eclipse.acceleo.aql.launcher/src/org/eclipse/acceleo/aql/launcher/AcceleoLauncher.java +++ b/plugins/org.eclipse.acceleo.aql.launcher/src/org/eclipse/acceleo/aql/launcher/AcceleoLauncher.java @@ -98,12 +98,28 @@ public class AcceleoLauncher implements IApplication { @Option(name = "-consoleLog", usage = "Log messages in the console.") private boolean consoleLog; + /** + * Output log URI. + */ + @Option(name = "-log", usage = "Specifies the module which main template will be executed.", metaVar = "LOG", handler = StringOptionHandler.class, required = false) + private String log; + /** List of URIs parsed from the {@link #models} argument. */ private List modelURIs; /** Bundle containing our main module for this generation. */ private Bundle bundle; + /** + * The target {@link URI}. + */ + private URI targetURI; + + /** + * The log {@link URI} if any, null otherwise. + */ + private URI logURI; + @Override public Object start(IApplicationContext context) throws Exception { String[] args = (String[])context.getArguments().get(IApplicationContext.APPLICATION_ARGS); @@ -141,7 +157,9 @@ public Object doMain(String[] args) { applicationResult = APPLICATION_ERROR; break; } - printDiagnostic(stream, result.getDiagnostic(), ""); + if (consoleLog) { + printDiagnostic(stream, result.getDiagnostic(), ""); + } } Set generatedFiles = result.getGeneratedFiles(); System.out.println("Generated " + generatedFiles.size() + " in " + target); @@ -183,7 +201,13 @@ private void validateArguments(CmdLineParser parser) throws CmdLineException { + " must be available in the target platform."); } try { - URI.createURI(target); + targetURI = URI.createURI(target); + } catch (IllegalArgumentException e) { + throw new CmdLineException(parser, e); + } + + try { + logURI = AcceleoUtil.getlogURI(targetURI, log); } catch (IllegalArgumentException e) { throw new CmdLineException(parser, e); } @@ -241,7 +265,8 @@ private GenerationResult launchGeneration() { } else { mainModule = null; } - evaluate(evaluator, queryEnvironment, mainModule, resourceSetForModels); + + evaluate(evaluator, queryEnvironment, mainModule, resourceSetForModels, targetURI, logURI); return evaluator.getGenerationResult(); } finally { AQLUtils.cleanResourceSetForModels(resolver, resourceSetForModels); @@ -250,11 +275,11 @@ private GenerationResult launchGeneration() { } private void evaluate(AcceleoEvaluator evaluator, IQualifiedNameQueryEnvironment queryEnvironment, - Module mainModule, ResourceSet modelResourceSet) { + Module mainModule, ResourceSet modelResourceSet, URI targetURI, URI logURI) { final IAcceleoGenerationStrategy strategy = new DefaultGenerationStrategy(modelResourceSet .getURIConverter()); - AcceleoUtil.generate(evaluator, queryEnvironment, mainModule, modelResourceSet, strategy, URI - .createURI(target)); + AcceleoUtil.generate(evaluator, queryEnvironment, mainModule, modelResourceSet, strategy, targetURI, + logURI); } private void printDiagnostic(PrintStream stream, Diagnostic diagnostic, String indentation) { diff --git a/plugins/org.eclipse.acceleo.aql.ls.debug.ide.ui/src/org/eclipse/acceleo/aql/ls/debug/ide/ui/launch/AcceleoMainTab.java b/plugins/org.eclipse.acceleo.aql.ls.debug.ide.ui/src/org/eclipse/acceleo/aql/ls/debug/ide/ui/launch/AcceleoMainTab.java index 472495a2a..d3b8ab76f 100644 --- a/plugins/org.eclipse.acceleo.aql.ls.debug.ide.ui/src/org/eclipse/acceleo/aql/ls/debug/ide/ui/launch/AcceleoMainTab.java +++ b/plugins/org.eclipse.acceleo.aql.ls.debug.ide.ui/src/org/eclipse/acceleo/aql/ls/debug/ide/ui/launch/AcceleoMainTab.java @@ -172,9 +172,9 @@ public void initializeFrom(ILaunchConfiguration configuration) { AcceleoDebugger.OPTION_MAP_TYPE); } else { options = new LinkedHashMap<>(); - if (!options.containsKey(AcceleoUtil.NEW_LINE_OPTION)) { - options.put(AcceleoUtil.NEW_LINE_OPTION, System.lineSeparator()); - } + options.put(AcceleoUtil.NEW_LINE_OPTION, System.lineSeparator()); + // TODO add GUI + options.put(AcceleoUtil.LOG_URI_OPTION, "acceleo.log"); } optionsString = GSON.toJson(options); initialOptionsString = optionsString; diff --git a/plugins/org.eclipse.acceleo.aql.ls.debug/src/org/eclipse/acceleo/aql/ls/debug/AcceleoDebugger.java b/plugins/org.eclipse.acceleo.aql.ls.debug/src/org/eclipse/acceleo/aql/ls/debug/AcceleoDebugger.java index 50a3328d5..73864c5e7 100644 --- a/plugins/org.eclipse.acceleo.aql.ls.debug/src/org/eclipse/acceleo/aql/ls/debug/AcceleoDebugger.java +++ b/plugins/org.eclipse.acceleo.aql.ls.debug/src/org/eclipse/acceleo/aql/ls/debug/AcceleoDebugger.java @@ -94,7 +94,7 @@ public void run() { final IAcceleoGenerationStrategy strategy = new DefaultGenerationStrategy(model .getResourceSet().getURIConverter()); AcceleoUtil.generate(evaluator, queryEnvironment, module, model, strategy, - getDestination()); + getDestination(), logURI); } } finally { // FIXME workaround: UI jobs are coming from core.debug even if the gen has finished, @@ -251,6 +251,11 @@ public Object doSwitch(EObject eObject) { */ private String newLine; + /** + * The log {@link URI} if any, null otherwise. + */ + private URI logURI; + /** * The {@link AcceleoDebugEvaluator}. */ @@ -297,6 +302,7 @@ public void initialize(boolean noDebug, Map arguments) { AcceleoParser.QUALIFIER_SEPARATOR, false); newLine = options.getOrDefault(AcceleoUtil.NEW_LINE_OPTION, System.lineSeparator()); + logURI = AcceleoUtil.getlogURI(destination, options.get(AcceleoUtil.LOG_URI_OPTION)); final ArrayList exceptions = new ArrayList<>(); resourceSetForModels = AQLUtils.createResourceSetForModels(exceptions, this, new ResourceSetImpl(), options); @@ -371,8 +377,8 @@ protected void generateNoDebug(IQualifiedNameQueryEnvironment environment, Modul final IAcceleoGenerationStrategy strategy = new DefaultGenerationStrategy(modelResource .getResourceSet().getURIConverter()); - AcceleoUtil.generate(noDebugEvaluator, environment, module, modelResource, strategy, - getDestination()); + AcceleoUtil.generate(noDebugEvaluator, environment, module, modelResource, strategy, getDestination(), + logURI); if (profiler != null) { try { diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/AcceleoUtil.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/AcceleoUtil.java index 161298b55..4ee816742 100644 --- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/AcceleoUtil.java +++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/AcceleoUtil.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -30,6 +31,7 @@ import org.eclipse.acceleo.Template; import org.eclipse.acceleo.aql.evaluation.AcceleoEvaluator; import org.eclipse.acceleo.aql.evaluation.writer.IAcceleoGenerationStrategy; +import org.eclipse.acceleo.aql.evaluation.writer.IAcceleoWriter; import org.eclipse.acceleo.query.AQLUtils; import org.eclipse.acceleo.query.ast.ASTNode; import org.eclipse.acceleo.query.ast.EClassifierTypeLiteral; @@ -41,6 +43,7 @@ import org.eclipse.acceleo.query.services.EObjectServices; import org.eclipse.acceleo.query.services.configurator.IServicesConfigurator; import org.eclipse.acceleo.util.AcceleoSwitch; +import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; @@ -65,6 +68,11 @@ public final class AcceleoUtil { */ public static final String NEW_LINE_OPTION = "newLine"; + /** + * The log URI {@link URI} {@link String} option name. + */ + public static final String LOG_URI_OPTION = "logURI"; + /** * "self". */ @@ -123,11 +131,14 @@ public static Template getMainTemplate(Module module) { * the {@link IAcceleoGenerationStrategy} * @param destination * destination {@link URI} + * @param logURI + * the {@link URI} for loggin if nay, null otherwise */ public static void generate(AcceleoEvaluator evaluator, IQualifiedNameQueryEnvironment queryEnvironment, - Module module, Resource model, IAcceleoGenerationStrategy generationStrategy, URI destination) { + Module module, Resource model, IAcceleoGenerationStrategy generationStrategy, URI destination, + URI logURI) { generate(evaluator, queryEnvironment, module, Collections.singletonList(model), generationStrategy, - destination); + destination, logURI); } /** @@ -145,17 +156,19 @@ public static void generate(AcceleoEvaluator evaluator, IQualifiedNameQueryEnvir * the {@link IAcceleoGenerationStrategy} * @param destination * the destination {@link URI} + * @param logURI + * the {@link URI} for loggin if nay, null otherwise */ public static void generate(AcceleoEvaluator evaluator, IQualifiedNameQueryEnvironment queryEnvironment, Module module, ResourceSet resourceSet, IAcceleoGenerationStrategy generationStrategy, - URI destination) { + URI destination, URI logURI) { generate(evaluator, queryEnvironment, module, resourceSet.getResources(), generationStrategy, - destination); + destination, logURI); } private static void generate(AcceleoEvaluator evaluator, IQualifiedNameQueryEnvironment queryEnvironment, Module module, List resources, IAcceleoGenerationStrategy generationStrategy, - URI destination) { + URI destination, URI logURI) { final EObjectServices services = new EObjectServices(queryEnvironment, null, null); final Template main = getMainTemplate(module); @@ -187,10 +200,38 @@ private static void generate(AcceleoEvaluator evaluator, IQualifiedNameQueryEnvi variables.put(parameterName, value); evaluator.generate(module, variables, generationStrategy, destination); } + + if (logURI != null && evaluator.getGenerationResult().getDiagnostic() + .getSeverity() != Diagnostic.OK) { + // TODO provide Charset and line delimiter + try { + final IAcceleoWriter logWriter = generationStrategy.createWriterForLog(logURI, + StandardCharsets.UTF_8, parameterName); + printDiagnostic(logWriter, evaluator.getGenerationResult().getDiagnostic(), "", System + .lineSeparator()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + generationStrategy.terminate(); } } + private static void printDiagnostic(IAcceleoWriter writer, Diagnostic diagnostic, String indentation, + String newLine) { + String nextIndentation = indentation; + if (diagnostic.getMessage() != null) { + writer.append(indentation); + writer.append(diagnostic.getMessage() + newLine); + nextIndentation += "\t"; + } + for (Diagnostic child : diagnostic.getChildren()) { + printDiagnostic(writer, child, nextIndentation, newLine); + } + } + /** * Provides the concrete Acceleo {@link EClass EClasses} that are, inherit or extend the given Acceleo * {@link EClass}. This is useful to use an {@link AcceleoSwitch} on non-instantiable EClasses. @@ -333,4 +374,36 @@ public static void cleanServices(IReadOnlyQueryEnvironment queryEnvironment, AQLUtils.cleanServices(LANGUAGE_NAME, queryEnvironment, resourceSetForModels); } + /** + * Gets the log {@link URI} for the given target {@link URI} and log {@link String}. + * + * @param targetURI + * the target {@link URI} + * @param log + * the log {@link String} + * @return the log {@link URI} for the given target {@link URI} and log {@link String} + * @throws IllegalArgumentException + * if {@link URI} convertion fails + */ + public static URI getlogURI(URI targetURI, String log) throws IllegalArgumentException { + final URI res; + + if (log != null) { + final URI uri = URI.createURI(log); + if (uri.isRelative()) { + if (targetURI.isRelative()) { + res = targetURI.appendSegments(uri.segments()); + } else { + res = uri.resolve(targetURI); + } + } else { + res = uri; + } + } else { + res = null; + } + + return res; + } + } diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/AcceleoEvaluator.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/AcceleoEvaluator.java index 60adfcfae..6d0d86204 100644 --- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/AcceleoEvaluator.java +++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/AcceleoEvaluator.java @@ -157,19 +157,6 @@ public class AcceleoEvaluator extends AcceleoSwitch { */ private String newLine; - /** - * Constructor. - * - * @param other - * the other {@link AcceleoEvaluator}. - */ - public AcceleoEvaluator(AcceleoEvaluator other) { - this(other.lookupEngine, other.newLine); - destination = other.destination; - generationStrategy = other.generationStrategy; - generationResult = other.generationResult; - } - /** * Constructor. * diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/DefaultGenerationStrategy.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/DefaultGenerationStrategy.java index 5e84aba74..45cb082ea 100644 --- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/DefaultGenerationStrategy.java +++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/DefaultGenerationStrategy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2023 Obeo. + * Copyright (c) 2008, 2024 Obeo. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -19,7 +19,6 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -44,7 +43,7 @@ public class DefaultGenerationStrategy implements IAcceleoGenerationStrategy { /** Used to call URIConverter methods with no options. */ - private static final Map EMPTY_OPTION_MAP = new HashMap<>(); + private static final Map EMPTY_OPTION_MAP = Collections.emptyMap(); /** * Keeps track of the contents of all protected areas from the files we've created writers for. @@ -115,6 +114,12 @@ public Map> consumeAllProtectedAreas(URI uri) { return res; } + @Override + public IAcceleoWriter createWriterForLog(URI uri, Charset charset, String lineDelimiter) + throws IOException { + return createWriterFor(uri, OpenModeKind.APPEND, charset, lineDelimiter); + } + @Override public IAcceleoWriter createWriterForLostContent(URI uri, String protectedAreaID, Charset charset, String lineDelimiter) throws IOException { diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/IAcceleoGenerationStrategy.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/IAcceleoGenerationStrategy.java index 85cdda772..634d30573 100644 --- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/IAcceleoGenerationStrategy.java +++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/IAcceleoGenerationStrategy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2023 Obeo. + * Copyright (c) 2008, 2024 Obeo. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -32,6 +32,7 @@ * @author Laurent Goubet */ public interface IAcceleoGenerationStrategy { + /** The start of user code String. Marks the start of a protected area. */ String USER_CODE_START = AcceleoMessages.getString("usercode.start"); //$NON-NLS-1$ @@ -72,6 +73,21 @@ public interface IAcceleoGenerationStrategy { */ Map> consumeAllProtectedAreas(URI uri); + /** + * Creates an {@link IAcceleoWriter} for the log content for the given destination {@link URI}. + * + * @param uri + * the log {@link URI} + * @param charset + * the {@link Charset} of the stream that's to be saved + * @param lineDelimiter + * the line delimiter that was demanded by the user for this writer. + * @throws IOException + * if the writer can't be created + * @return the created writer. It can't be null use {@link NullWriter} instead. + */ + IAcceleoWriter createWriterForLog(URI uri, Charset charset, String lineDelimiter) throws IOException; + /** * Creates an {@link IAcceleoWriter} for the lost content for the given generated {@link URI} with the * given protected area ID. @@ -83,6 +99,7 @@ public interface IAcceleoGenerationStrategy { * @param charset * the {@link Charset} of the stream that's to be saved * @param lineDelimiter + * the line delimiter that was demanded by the user for this writer. * @throws IOException * if the writer can't be created * @return the created writer. It can't be null use {@link NullWriter} instead. diff --git a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/NullGenerationStrategy.java b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/NullGenerationStrategy.java index c13e45a5a..046131fc2 100644 --- a/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/NullGenerationStrategy.java +++ b/plugins/org.eclipse.acceleo.aql/src/org/eclipse/acceleo/aql/evaluation/writer/NullGenerationStrategy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2023 Obeo. + * Copyright (c) 2017, 2024 Obeo. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -41,6 +41,12 @@ public Map> consumeAllProtectedAreas(URI uri) { return Collections.emptyMap(); } + @Override + public IAcceleoWriter createWriterForLog(URI uri, Charset charset, String lineDelimiter) + throws IOException { + return new NullWriter(uri, charset); + } + @Override public IAcceleoWriter createWriterForLostContent(URI uri, String protectedAreaID, Charset charset, String lineDelimiter) throws IOException { diff --git a/tests/org.eclipse.acceleo.aql.tests/src/org/eclipse/acceleo/tests/utils/AbstractEvaluationTestSuite.java b/tests/org.eclipse.acceleo.aql.tests/src/org/eclipse/acceleo/tests/utils/AbstractEvaluationTestSuite.java index 27af969fc..c7114204d 100644 --- a/tests/org.eclipse.acceleo.aql.tests/src/org/eclipse/acceleo/tests/utils/AbstractEvaluationTestSuite.java +++ b/tests/org.eclipse.acceleo.aql.tests/src/org/eclipse/acceleo/tests/utils/AbstractEvaluationTestSuite.java @@ -115,7 +115,7 @@ public void evaluation() throws IOException { final List unexpectedGeneratedFiles = new ArrayList(); final IAcceleoGenerationStrategy strategy = new DefaultGenerationStrategy(model.getResourceSet() .getURIConverter()); - AcceleoUtil.generate(evaluator, queryEnvironment, module, model, strategy, memoryDestination); + AcceleoUtil.generate(evaluator, queryEnvironment, module, model, strategy, memoryDestination, null); assertGenerationMessages(evaluator.getGenerationResult()); @@ -183,7 +183,7 @@ public void evaluationWindowsEndLine() throws IOException { final IAcceleoGenerationStrategy strategy = new DefaultGenerationStrategy(model.getResourceSet() .getURIConverter()); AcceleoUtil.generate(evaluatorWindowsEndLine, queryEnvironmentWindowsEndLine, module, model, strategy, - memoryDestination); + memoryDestination, null); assertGenerationMessagesWindowsEndLine(evaluatorWindowsEndLine.getGenerationResult());