mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 16:58:56 +00:00
[generator] Added templates for manifest and activator
Signed-off-by: Miro Spönemann <miro.spoenemann@itemis.de>
This commit is contained in:
parent
54b42f3305
commit
84b71efadf
5 changed files with 220 additions and 17 deletions
|
@ -11,6 +11,11 @@ import com.google.inject.Guice
|
|||
import com.google.inject.Inject
|
||||
import com.google.inject.Injector
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.List
|
||||
import org.eclipse.emf.mwe.core.WorkflowContext
|
||||
import org.eclipse.emf.mwe.core.issues.Issues
|
||||
|
@ -18,9 +23,12 @@ import org.eclipse.emf.mwe.core.lib.AbstractWorkflowComponent2
|
|||
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtext.XtextStandaloneSetup
|
||||
import org.eclipse.xtext.util.MergeableManifest
|
||||
import org.eclipse.xtext.xtext.generator.model.CodeConfig
|
||||
import org.eclipse.xtext.xtext.generator.model.IXtextProjectConfig
|
||||
import org.eclipse.xtext.xtext.generator.model.ManifestAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.PluginXmlAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.TypeReference
|
||||
|
||||
/**
|
||||
* The Xtext language infrastructure generator. Can be configured with {@link IGeneratorFragment}
|
||||
|
@ -40,6 +48,8 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
|
|||
|
||||
Injector injector
|
||||
|
||||
@Inject extension XtextGeneratorNaming
|
||||
|
||||
@Inject IXtextProjectConfig projectConfig
|
||||
|
||||
@Inject XtextGeneratorTemplates templates
|
||||
|
@ -87,6 +97,7 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
|
|||
}
|
||||
generatePluginXmls()
|
||||
generateManifests()
|
||||
generateActivator()
|
||||
}
|
||||
|
||||
protected def generateRuntimeSetup(LanguageConfig2 language) {
|
||||
|
@ -109,16 +120,67 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
|
|||
}
|
||||
|
||||
protected def generateManifests() {
|
||||
projectConfig.runtimeManifest?.generate()
|
||||
projectConfig.runtimeTestManifest?.generate()
|
||||
projectConfig.genericIdeManifest?.generate()
|
||||
projectConfig.genericIdeTestManifest?.generate()
|
||||
projectConfig.eclipsePluginManifest?.generate()
|
||||
projectConfig.eclipsePluginTestManifest?.generate()
|
||||
projectConfig.ideaPluginManifest?.generate()
|
||||
projectConfig.ideaPluginTestManifest?.generate()
|
||||
projectConfig.webManifest?.generate()
|
||||
projectConfig.webTestManifest?.generate()
|
||||
val firstGrammar = languageConfigs.head?.grammar
|
||||
generateManifest(projectConfig.runtimeManifest, null)
|
||||
generateManifest(projectConfig.runtimeTestManifest, null)
|
||||
generateManifest(projectConfig.genericIdeManifest, null)
|
||||
generateManifest(projectConfig.genericIdeTestManifest, null)
|
||||
generateManifest(projectConfig.eclipsePluginManifest, firstGrammar.eclipsePluginActivator)
|
||||
generateManifest(projectConfig.eclipsePluginTestManifest, null)
|
||||
generateManifest(projectConfig.ideaPluginManifest, null)
|
||||
generateManifest(projectConfig.ideaPluginTestManifest, null)
|
||||
generateManifest(projectConfig.webManifest, null)
|
||||
generateManifest(projectConfig.webTestManifest, null)
|
||||
}
|
||||
|
||||
protected def generateManifest(ManifestAccess manifest, TypeReference activator) {
|
||||
if (manifest !== null) {
|
||||
if (manifest.bundleName === null) {
|
||||
val segments = manifest.path.split('/')
|
||||
if (segments.length >= 3 && segments.get(segments.length - 2) == 'META-INF')
|
||||
manifest.bundleName = segments.get(segments.length - 3)
|
||||
}
|
||||
val file = new File(manifest.path)
|
||||
if (file.exists) {
|
||||
if (manifest.merge) {
|
||||
mergeManifest(manifest, file, activator)
|
||||
} else if (manifest.path.endsWith('.MF')) {
|
||||
manifest.path = manifest.path + '_gen'
|
||||
templates.createManifest(manifest, activator).writeToFile()
|
||||
}
|
||||
} else {
|
||||
templates.createManifest(manifest, activator).writeToFile()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def generateActivator() {
|
||||
if (projectConfig.eclipsePluginSrcGen !== null)
|
||||
templates.createEclipsePluginActivator(languageConfigs).writeTo(projectConfig.eclipsePluginSrcGen)
|
||||
}
|
||||
|
||||
protected def mergeManifest(ManifestAccess manifest, File file, TypeReference activator) throws IOException {
|
||||
var InputStream in
|
||||
var OutputStream out
|
||||
try {
|
||||
in = new FileInputStream(file)
|
||||
val merge = new MergeableManifest(in, manifest.bundleName)
|
||||
merge.addExportedPackages(manifest.exportedPackages)
|
||||
merge.addRequiredBundles(manifest.requiredBundles)
|
||||
merge.addImportedPackages(manifest.importedPackages)
|
||||
if (activator !== null && !merge.mainAttributes.containsKey(MergeableManifest.BUNDLE_ACTIVATOR)) {
|
||||
merge.mainAttributes.put(MergeableManifest.BUNDLE_ACTIVATOR, activator.name)
|
||||
}
|
||||
if (merge.isModified) {
|
||||
out = new FileOutputStream(file)
|
||||
merge.write(out)
|
||||
}
|
||||
} finally {
|
||||
if (in !== null)
|
||||
in.close()
|
||||
if (out != null)
|
||||
out.close()
|
||||
}
|
||||
}
|
||||
|
||||
protected def generatePluginXmls() {
|
||||
|
|
|
@ -7,13 +7,16 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator
|
||||
|
||||
import com.google.common.collect.Maps
|
||||
import com.google.inject.Binder
|
||||
import com.google.inject.Guice
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Injector
|
||||
import com.google.inject.Module
|
||||
import com.google.inject.Provider
|
||||
import com.google.inject.Singleton
|
||||
import com.google.inject.name.Names
|
||||
import java.util.List
|
||||
import org.eclipse.xtext.Constants
|
||||
import org.eclipse.xtext.ISetup
|
||||
import org.eclipse.xtext.ISetupExtension
|
||||
|
@ -21,11 +24,14 @@ import org.eclipse.xtext.XtextPackage
|
|||
import org.eclipse.xtext.parser.IEncodingProvider
|
||||
import org.eclipse.xtext.resource.impl.BinaryGrammarResourceFactoryImpl
|
||||
import org.eclipse.xtext.service.SingletonBinding
|
||||
import org.eclipse.xtext.util.Modules2
|
||||
import org.eclipse.xtext.xtext.generator.model.CodeConfig
|
||||
import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.JavaFileAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.ManifestAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.PluginXmlAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.TextFileAccess
|
||||
import org.eclipse.xtext.xtext.generator.model.TypeReference
|
||||
|
||||
@Singleton
|
||||
class XtextGeneratorTemplates {
|
||||
|
@ -93,6 +99,7 @@ class XtextGeneratorTemplates {
|
|||
«FOR usedGrammar : g.usedGrammars»
|
||||
«usedGrammar.runtimeSetup».doSetup();
|
||||
«ENDFOR»
|
||||
|
||||
«IF g.usedGrammars.isEmpty»
|
||||
// register default ePackages
|
||||
if (!«'org.eclipse.emf.ecore.resource.Resource'».Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("ecore"))
|
||||
|
@ -270,6 +277,36 @@ class XtextGeneratorTemplates {
|
|||
return javaFile
|
||||
}
|
||||
|
||||
def TextFileAccess createManifest(ManifestAccess manifest, TypeReference activator) {
|
||||
val file = new TextFileAccess
|
||||
file.encodingProvider = encodingProvider
|
||||
file.path = manifest.path
|
||||
file.content = '''
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: «manifest.bundleName»
|
||||
Bundle-SymbolicName: «manifest.symbolicName ?: manifest.bundleName»; singleton:=true
|
||||
«IF !manifest.version.nullOrEmpty»
|
||||
Bundle-Version: «manifest.version»
|
||||
«ENDIF»
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Bundle-ActivationPolicy: lazy
|
||||
«IF !manifest.exportedPackages.empty»
|
||||
Export-Package: «FOR pack : manifest.exportedPackages.sort SEPARATOR ',\n '»«pack»«ENDFOR»
|
||||
«ENDIF»
|
||||
«IF !manifest.requiredBundles.empty»
|
||||
Require-Bundle: «FOR bundle : manifest.requiredBundles.sort SEPARATOR ',\n '»«bundle»«ENDFOR»
|
||||
«ENDIF»
|
||||
«IF !manifest.importedPackages.empty»
|
||||
Import-Package: «FOR pack : manifest.importedPackages.sort SEPARATOR ',\n '»«pack»«ENDFOR»
|
||||
«ENDIF»
|
||||
«IF activator !== null»
|
||||
Bundle-Activator: «activator»
|
||||
«ENDIF»
|
||||
'''
|
||||
return file
|
||||
}
|
||||
|
||||
def JavaFileAccess createEclipsePluginExecutableExtensionFactory(LanguageConfig2 langConfig) {
|
||||
val g = langConfig.grammar
|
||||
val javaFile = new JavaFileAccess(g.eclipsePluginExecutableExtensionFactory, codeConfig)
|
||||
|
@ -300,4 +337,98 @@ class XtextGeneratorTemplates {
|
|||
return javaFile
|
||||
}
|
||||
|
||||
def JavaFileAccess createEclipsePluginActivator(List<LanguageConfig2> langConfigs) {
|
||||
val gs = langConfigs.map[grammar].toList
|
||||
val activator = gs.head.eclipsePluginActivator
|
||||
val javaFile = new JavaFileAccess(activator, codeConfig)
|
||||
javaFile.encodingProvider = encodingProvider
|
||||
|
||||
javaFile.typeComment = '''
|
||||
/**
|
||||
* This class was generated. Customizations should only happen in a newly
|
||||
* introduced subclass.
|
||||
*/
|
||||
'''
|
||||
javaFile.javaContent = '''
|
||||
public class «activator.simpleName» extends «'org.eclipse.ui.plugin.AbstractUIPlugin'» {
|
||||
|
||||
«FOR grammar : gs»
|
||||
public static final String «grammar.name.toUpperCase.replaceAll('\\.', '_')» = "«grammar.name»";
|
||||
«ENDFOR»
|
||||
|
||||
private static final Logger logger = Logger.getLogger(«activator.simpleName».class);
|
||||
|
||||
private static «activator.simpleName» INSTANCE;
|
||||
|
||||
private «'java.util.Map'»<String, «Injector»> injectors = «'java.util.Collections'».synchronizedMap(«Maps».<String, «Injector»> newHashMapWithExpectedSize(1));
|
||||
|
||||
@Override
|
||||
public void start(«'org.osgi.framework.BundleContext'» context) throws Exception {
|
||||
super.start(context);
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(«'org.osgi.framework.BundleContext'» context) throws Exception {
|
||||
injectors.clear();
|
||||
INSTANCE = null;
|
||||
super.stop(context);
|
||||
}
|
||||
|
||||
public static «activator.simpleName» getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public «Injector» getInjector(String language) {
|
||||
synchronized (injectors) {
|
||||
«Injector» injector = injectors.get(language);
|
||||
if (injector == null) {
|
||||
injectors.put(language, injector = createInjector(language));
|
||||
}
|
||||
return injector;
|
||||
}
|
||||
}
|
||||
|
||||
protected «Injector» createInjector(String language) {
|
||||
try {
|
||||
«Module» runtimeModule = getRuntimeModule(language);
|
||||
«Module» sharedStateModule = getSharedStateModule();
|
||||
«Module» uiModule = getUiModule(language);
|
||||
«Module» mergedModule = «Modules2».mixin(runtimeModule, sharedStateModule, uiModule);
|
||||
return «Guice».createInjector(mergedModule);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to create injector for " + language);
|
||||
logger.error(e.getMessage(), e);
|
||||
throw new RuntimeException("Failed to create injector for " + language, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Module getRuntimeModule(String grammar) {
|
||||
«FOR grammar : gs»
|
||||
if («grammar.name.toUpperCase.replaceAll('\\.', '_')».equals(grammar)) {
|
||||
return new «grammar.runtimeModule»();
|
||||
}
|
||||
«ENDFOR»
|
||||
throw new IllegalArgumentException(grammar);
|
||||
}
|
||||
|
||||
protected «Module» getUiModule(String grammar) {
|
||||
«FOR grammar : gs»
|
||||
if («grammar.name.toUpperCase.replaceAll('\\.', '_')».equals(grammar)) {
|
||||
return new «grammar.eclipsePluginModule»(this);
|
||||
}
|
||||
«ENDFOR»
|
||||
throw new IllegalArgumentException(grammar);
|
||||
}
|
||||
|
||||
protected «Module» getSharedStateModule() {
|
||||
return new «'org.eclipse.xtext.ui.shared.SharedStateModule'»();
|
||||
}
|
||||
|
||||
}
|
||||
'''
|
||||
javaFile.markedAsGenerated = true
|
||||
return javaFile
|
||||
}
|
||||
|
||||
}
|
|
@ -7,17 +7,26 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.model
|
||||
|
||||
import java.util.Set
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
|
||||
@Accessors
|
||||
class ManifestAccess {
|
||||
|
||||
String path
|
||||
String path = 'META-INF/MANIFEST.MF'
|
||||
|
||||
boolean merge
|
||||
String bundleName
|
||||
|
||||
def void generate() {
|
||||
|
||||
}
|
||||
String symbolicName
|
||||
|
||||
String version = '0.0.1'
|
||||
|
||||
boolean merge = true
|
||||
|
||||
val Set<String> exportedPackages = newHashSet
|
||||
|
||||
val Set<String> requiredBundles = newHashSet
|
||||
|
||||
val Set<String> importedPackages = newHashSet
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.eclipse.xtend.lib.annotations.Accessors
|
|||
@Accessors
|
||||
class PluginXmlAccess {
|
||||
|
||||
String path
|
||||
String path = 'plugin.xml'
|
||||
|
||||
val List<CharSequence> entries = newArrayList
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.eclipse.xtext.xtext.generator.model
|
|||
|
||||
import com.google.common.io.Files
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.nio.charset.Charset
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
|
@ -34,7 +35,7 @@ class TextFileAccess {
|
|||
fileSystemAccess.generateFile(path, generate())
|
||||
}
|
||||
|
||||
def writeToFile() {
|
||||
def writeToFile() throws IOException {
|
||||
var Charset charset
|
||||
if (encodingProvider !== null) {
|
||||
val uri = URI.createFileURI(path)
|
||||
|
|
Loading…
Reference in a new issue