diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
new file mode 100644
index 000000000..6c19e9b4b
--- /dev/null
+++ b/.mvn/extensions.xml
@@ -0,0 +1,8 @@
+
+
+
+ org.eclipse.tycho
+ tycho-build
+ ${tycho.version}
+
+
diff --git a/.mvn/maven.config b/.mvn/maven.config
new file mode 100644
index 000000000..41217c968
--- /dev/null
+++ b/.mvn/maven.config
@@ -0,0 +1 @@
+-Dtycho.version=5.0.2
diff --git a/AGENTS.md b/AGENTS.md
index 77ea18a9d..6fe4580db 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -68,6 +68,21 @@ export WORKSPACE=$(pwd)
- **Aggregator module**: `com.avaloq.tools.ddk.xtext.test`
- **UI tests**: Require virtual display (xvfb on Linux) or `-XstartOnFirstThread` (macOS)
+### macOS developer setup
+
+SWT on Cocoa requires the Display to be created on the main thread. UI tests
+therefore need `-XstartOnFirstThread`. There are two contexts:
+
+- **`mvn verify` / CI**: the `macosx` profile in `ddk-parent/pom.xml` (activated
+ on `family=mac`) adds the flag automatically. No setup required.
+- **Running launches from Eclipse**: add `-XstartOnFirstThread` to your JRE's
+ default VM arguments — `Window > Preferences > Java > Installed JREs > [your
+ JDK] > Edit > Default VM arguments`. PDE launches with `append.args=true`
+ inherit this on macOS only. The flag is not hardcoded in the `.launch` files
+ because the JVM on Windows and Linux rejects it as an "Unrecognized VM
+ option". This matches Eclipse Platform's own UI test launches (which omit
+ the flag and rely on the same JRE-default-args mechanism).
+
### Aggregator pattern — important
The project runs **all tests through one aggregator module**, not per-`.test`-module. `ddk-parent/pom.xml` sets `true` on `tycho-surefire-plugin` globally; only `com.avaloq.tools.ddk.xtext.test` overrides it with its own full tycho-surefire configuration. Inside that module, `src/com/avaloq/tools/ddk/xtext/AllTests.java` is a JUnit 5 `@Suite` that `@SelectClasses` from ~14 per-module `*TestSuite` classes (`ExportTestSuite`, `CheckCoreTestSuite`, `TypeSystemTestSuite`, `CheckUiTestSuite`, etc.). Those other `.test` bundles are on `xtext.test`'s OSGi classpath via `Require-Bundle`, so their test classes get discovered and executed inside the single Eclipse runtime spun up for `xtext.test`.
diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend
index be2ed319b..083ddc9b2 100644
--- a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend
+++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/CheckGenerator.xtend
@@ -16,6 +16,7 @@ import com.google.inject.Inject
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.AbstractFileSystemAccess
import org.eclipse.xtext.generator.IFileSystemAccess
+import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.xbase.compiler.JvmModelGenerator
import static org.eclipse.xtext.xbase.lib.IteratorExtensions.*
@@ -36,15 +37,16 @@ class CheckGenerator extends JvmModelGenerator {
@Inject ICheckGeneratorConfigProvider generatorConfigProvider;
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
- super.doGenerate(resource, fsa); // Generate validator, catalog, and preference initializer from inferred Jvm models.
+ val lfFsa = new LfNormalizingFileSystemAccess(fsa as IFileSystemAccess2)
+ super.doGenerate(resource, lfFsa); // Generate validator, catalog, and preference initializer from inferred Jvm models.
val config = generatorConfigProvider.get(resource?.URI);
for (catalog : toIterable(resource.allContents).filter(typeof(CheckCatalog))) {
- fsa.generateFile(catalog.issueCodesFilePath, catalog.compileIssueCodes)
- fsa.generateFile(catalog.standaloneSetupPath, catalog.compileStandaloneSetup)
+ lfFsa.generateFile(catalog.issueCodesFilePath, catalog.compileIssueCodes)
+ lfFsa.generateFile(catalog.standaloneSetupPath, catalog.compileStandaloneSetup)
// change output path for service registry
- fsa.generateFile(
+ lfFsa.generateFile(
CheckUtil::serviceRegistryClassName,
CheckGeneratorConstants::CHECK_REGISTRY_OUTPUT,
catalog.generateServiceRegistry(CheckUtil::serviceRegistryClassName, fsa)
@@ -52,7 +54,7 @@ class CheckGenerator extends JvmModelGenerator {
// generate documentation for SCA-checks only
if(config !== null && (config.doGenerateDocumentationForAllChecks || !config.generateLanguageInternalChecks)){
// change output path for html files to docs/
- fsa.generateFile(catalog.docFileName, CheckGeneratorConstants::CHECK_DOC_OUTPUT, catalog.compileDoc)
+ lfFsa.generateFile(catalog.docFileName, CheckGeneratorConstants::CHECK_DOC_OUTPUT, catalog.compileDoc)
}
}
}
diff --git a/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/LfNormalizingFileSystemAccess.java b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/LfNormalizingFileSystemAccess.java
new file mode 100644
index 000000000..53dbd1f2a
--- /dev/null
+++ b/com.avaloq.tools.ddk.check.core/src/com/avaloq/tools/ddk/check/generator/LfNormalizingFileSystemAccess.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Avaloq Group AG and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Avaloq Group AG - initial API and implementation
+ *******************************************************************************/
+
+package com.avaloq.tools.ddk.check.generator;
+
+import java.io.InputStream;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.xtext.generator.IFileSystemAccess2;
+
+import com.google.common.base.Preconditions;
+
+
+/**
+ * A delegating {@link IFileSystemAccess2} that normalizes line endings to LF ({@code \n})
+ * before writing content. This ensures generated files are platform-independent regardless
+ * of the OS on which the build runs.
+ *
+ *
Implements {@link IFileSystemAccess2} so that {@code instanceof} checks in the framework
+ * (e.g., in {@code JvmModelGenerator}) continue to work and no behavior is lost.
+ */
+public class LfNormalizingFileSystemAccess implements IFileSystemAccess2 {
+
+ private final IFileSystemAccess2 delegate;
+
+ /**
+ * Wraps the given delegate. Callers that hold the weaker {@link org.eclipse.xtext.generator.IFileSystemAccess}
+ * (e.g. from Xtext's {@code Generator2#doGenerate(Resource, IFileSystemAccess)}) must cast at the
+ * call site — every default Xtext FSA implementation is also an {@link IFileSystemAccess2}.
+ *
+ * @param delegate the delegate to wrap, must not be {@code null}
+ */
+ public LfNormalizingFileSystemAccess(final IFileSystemAccess2 delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ }
+
+ @Override
+ public void generateFile(final String fileName, final CharSequence contents) {
+ delegate.generateFile(fileName, normalizeLineEndings(contents));
+ }
+
+ @Override
+ public void generateFile(final String fileName, final String outputConfigName, final CharSequence contents) {
+ delegate.generateFile(fileName, outputConfigName, normalizeLineEndings(contents));
+ }
+
+ @Override
+ public void deleteFile(final String fileName) {
+ delegate.deleteFile(fileName);
+ }
+
+ @Override
+ public void generateFile(final String fileName, final InputStream content) {
+ delegate.generateFile(fileName, content);
+ }
+
+ @Override
+ public void generateFile(final String fileName, final String outputConfigName, final InputStream content) {
+ delegate.generateFile(fileName, outputConfigName, content);
+ }
+
+ @Override
+ public URI getURI(final String fileName, final String outputConfigName) {
+ return delegate.getURI(fileName, outputConfigName);
+ }
+
+ @Override
+ public URI getURI(final String fileName) {
+ return delegate.getURI(fileName);
+ }
+
+ @Override
+ public void deleteFile(final String fileName, final String outputConfigName) {
+ delegate.deleteFile(fileName, outputConfigName);
+ }
+
+ @Override
+ public InputStream readBinaryFile(final String fileName, final String outputConfigName) {
+ return delegate.readBinaryFile(fileName, outputConfigName);
+ }
+
+ @Override
+ public InputStream readBinaryFile(final String fileName) {
+ return delegate.readBinaryFile(fileName);
+ }
+
+ @Override
+ public CharSequence readTextFile(final String fileName, final String outputConfigName) {
+ return delegate.readTextFile(fileName, outputConfigName);
+ }
+
+ @Override
+ public CharSequence readTextFile(final String fileName) {
+ return delegate.readTextFile(fileName);
+ }
+
+ @Override
+ public boolean isFile(final String path, final String outputConfigurationName) {
+ return delegate.isFile(path, outputConfigurationName);
+ }
+
+ @Override
+ public boolean isFile(final String path) {
+ return delegate.isFile(path);
+ }
+
+ private static CharSequence normalizeLineEndings(final CharSequence content) {
+ if (content == null) {
+ return null;
+ }
+ String text = content.toString();
+ if (text.indexOf('\r') < 0) {
+ return content;
+ }
+ return text.replace("\r\n", "\n").replace("\r", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+}
diff --git a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend
index 9b305ef40..e7a49aa53 100644
--- a/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend
+++ b/com.avaloq.tools.ddk.checkcfg.core/src/com/avaloq/tools/ddk/checkcfg/generator/CheckCfgGenerator.xtend
@@ -10,12 +10,14 @@
*******************************************************************************/
package com.avaloq.tools.ddk.checkcfg.generator
+import com.avaloq.tools.ddk.check.generator.LfNormalizingFileSystemAccess
import com.avaloq.tools.ddk.check.runtime.configuration.ICheckConfigurationStoreService
import com.avaloq.tools.ddk.checkcfg.checkcfg.CheckConfiguration
import com.google.inject.Inject
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.AbstractFileSystemAccess
import org.eclipse.xtext.generator.IFileSystemAccess
+import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.generator.IGenerator
import static org.eclipse.xtext.xbase.lib.IteratorExtensions.*
@@ -37,8 +39,9 @@ class CheckCfgGenerator implements IGenerator {
if (fsa instanceof AbstractFileSystemAccess) {
fsa.setOutputPath(outputPath)
}
+ val lfFsa = new LfNormalizingFileSystemAccess(fsa as IFileSystemAccess2)
for (configuration:toIterable(resource.allContents).filter(typeof(CheckConfiguration))) {
- fsa.generateFile(configuration.fileName, configuration.compile)
+ lfFsa.generateFile(configuration.fileName, configuration.compile)
}
}
diff --git a/com.avaloq.tools.ddk.xtext.export.test/pom.xml b/com.avaloq.tools.ddk.xtext.export.test/pom.xml
index aad43622d..71bae1bae 100644
--- a/com.avaloq.tools.ddk.xtext.export.test/pom.xml
+++ b/com.avaloq.tools.ddk.xtext.export.test/pom.xml
@@ -10,4 +10,85 @@
com.avaloq.tools.ddk.xtext.export.test
eclipse-test-plugin
-
\ No newline at end of file
+
+
+
+
+ org.eclipse.tycho
+ tycho-surefire-plugin
+ ${tycho.version}
+
+ false
+ ${ddk.skipPerModuleTests}
+ com.avaloq.tools.ddk.xtext.test.export.ExportTestSuite
+ false
+ false
+ true
+ ${test.timeout}
+
+ -Dorg.osgi.framework.system.packages.extra=jdk.incubator.vector -Dslf4j.internal.verbosity=ERROR -Dlogback.configurationFile="${runtime.logbackConfig}" ${test.javaOptions}
+ -pluginCustomization ${runtime.pluginCustomization}
+ ${runtime.product}
+ org.eclipse.ui.ide.workbench
+
+
+ p2-installable-unit
+ org.eclipse.platform.feature.group
+
+
+
+
+
+ org.eclipse.tycho
+ target-platform-configuration
+ ${tycho.version}
+
+
+
+
+ eclipse-feature
+ org.eclipse.xtext.sdk
+ 0.0.0
+
+
+ eclipse-feature
+ org.eclipse.pde
+ 0.0.0
+
+
+ eclipse-feature
+ org.eclipse.help
+ 0.0.0
+
+
+ eclipse-feature
+ org.eclipse.rcp
+ 0.0.0
+
+
+ eclipse-plugin
+ org.eclipse.equinox.event
+ 0.0.0
+
+
+
+
+
+
+
+
diff --git a/ddk-parent/pom.xml b/ddk-parent/pom.xml
index a32edb44c..061b270e7 100644
--- a/ddk-parent/pom.xml
+++ b/ddk-parent/pom.xml
@@ -56,6 +56,17 @@
7.24.0
5.0.2
2.42.0
+
+
+ true
@@ -425,5 +436,19 @@
x86_64
+
+ macosx
+
+
+ mac
+
+
+
+ macosx
+ cocoa
+ aarch64
+ ${runtime.javaOptions} -XstartOnFirstThread
+
+