[generator] Added templates for manifest and activator

Signed-off-by: Miro Spönemann <miro.spoenemann@itemis.de>
This commit is contained in:
Miro Spönemann 2015-07-06 14:55:52 +02:00
parent 54b42f3305
commit 84b71efadf
5 changed files with 220 additions and 17 deletions

View file

@ -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() {

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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)