use of com.devonfw.cobigen.api.extension.Merger in project cobigen by devonfw.
the class TypeScriptMergerTest method testMergingOverridesExportConst.
/**
* Checks if the ts-merger can merge an export const with patchOverrides = true correctly
*
* Check: https://github.com/devonfw/cobigen/issues/1291
*/
@Test
public void testMergingOverridesExportConst() {
// arrange
Merger tsMerger = this.activator.bindMerger().stream().filter(e -> e.getType().equals(TypeScriptPluginActivator.TSMERGE_OVERRIDE)).findFirst().get();
File baseFile = new File(testFileRootPath + "export_const_base.ts");
// act
String mergedContents = tsMerger.merge(baseFile, readTSFile("export_const_patch.ts"), "UTF-8");
// Should merge properly
assertThat(mergedContents).contains("export const test = {");
assertThat(mergedContents).contains("a: false");
assertThat(mergedContents).contains("b: true");
}
use of com.devonfw.cobigen.api.extension.Merger in project cobigen by devonfw.
the class PluginRegistry method getMerger.
/**
* Returns the {@link Merger} for the given merge strategy
*
* @param mergeStrategy the {@link Merger} should be able to interpret
* @return the {@link Merger} for the given mergerType or <code>null</code> if there is no {@link Merger} for this
* mergerType
*/
public static Merger getMerger(String mergeStrategy) {
if (mergeStrategy == null) {
return null;
}
Merger merger = registeredMerger.get(mergeStrategy);
if (merger == null) {
LOG.debug("Trying to find merger for type '{}' in {} registered plugins.", mergeStrategy, ClassServiceLoader.getGeneratorPluginActivatorClasses().size());
for (Class<? extends GeneratorPluginActivator> activatorClass : ClassServiceLoader.getGeneratorPluginActivatorClasses()) {
LOG.debug("Checking found plug-in activator '{}'", activatorClass);
if (activatorClass.isAnnotationPresent(Activation.class)) {
Activation activation = activatorClass.getAnnotation(Activation.class);
String[] byMergeStrategy = activation.byMergeStrategy();
if (LOG.isDebugEnabled()) {
LOG.debug("Plug-in will be activated by merge strategies '{}'.", Arrays.stream(byMergeStrategy).collect(Collectors.joining(",")));
}
Arrays.sort(byMergeStrategy);
if (Arrays.binarySearch(byMergeStrategy, mergeStrategy) >= 0) {
loadPlugin(activatorClass);
break;
} else {
LOG.debug("Merge strategy not found. Skipping.");
}
} else {
LOG.debug("Activator annotation not present. Skipping.");
}
}
merger = registeredMerger.get(mergeStrategy);
}
if (merger != null) {
merger = ProxyFactory.getProxy(merger);
}
return merger;
}
use of com.devonfw.cobigen.api.extension.Merger in project cobigen by devonfw.
the class PluginRegistry method loadPlugin.
/**
* Loads the given plug-in and registers all {@link Merger}s and {@link TriggerInterpreter}s bound by the given
* plug-in
*
* @param generatorPlugin plug-in to be loaded
* @param <T> Type of the plug-in interface
* @return the instantiated {@link GeneratorPluginActivator}
*/
private static <T extends GeneratorPluginActivator> GeneratorPluginActivator loadPlugin(Class<T> generatorPlugin) {
try {
Object plugin = generatorPlugin.newInstance();
LOG.info("Register CobiGen Plug-in '{}'.", generatorPlugin.getCanonicalName());
if (plugin instanceof GeneratorPluginActivator) {
// Collect Mergers
GeneratorPluginActivator activator = (GeneratorPluginActivator) plugin;
if (activator.bindMerger() != null) {
for (Merger merger : activator.bindMerger()) {
registerMerger(merger);
}
// adds merger plugins to notifyable list
}
// Collect TriggerInterpreters
if (activator.bindTriggerInterpreter() != null) {
for (TriggerInterpreter triggerInterpreter : activator.bindTriggerInterpreter()) {
registerTriggerInterpreter(triggerInterpreter, activator);
}
}
loadedPlugins.put(activator.getClass(), activator);
return activator;
} else {
LOG.warn("Instantiated plugin of class {}, which is not subclass of {}", plugin.getClass().getCanonicalName(), GeneratorPluginActivator.class.getCanonicalName());
return null;
}
} catch (InstantiationException | IllegalAccessException e) {
throw new CobiGenRuntimeException("Could not intantiate CobiGen Plug-in '" + generatorPlugin.getCanonicalName() + "'.", e);
}
}
use of com.devonfw.cobigen.api.extension.Merger in project cobigen by devonfw.
the class GenerationProcessorImpl method generate.
/**
* Generates code for the given input with the given template and the given {@link TriggerInterpreter} to the
* destination specified by the templates configuration.
*
* @param template to be processed for generation
* @param triggerInterpreter {@link TriggerInterpreter} to be used for reading the input and creating the model
* @param origToTmpFileTrace the mapping of temporary generated files to their original target destination to
* eventually finalizing the generation process
* @param progressCallback to track progress
* @throws InvalidConfigurationException if the inputs do not fit to the configuration or there are some configuration
* failures
*/
private void generate(TemplateTo template, TriggerInterpreter triggerInterpreter, Map<File, File> origToTmpFileTrace, BiConsumer<String, Integer> progressCallback) {
Trigger trigger = this.configurationHolder.readContextConfiguration().getTrigger(template.getTriggerId());
InputReader inputReader = triggerInterpreter.getInputReader();
if (!inputReader.isValidInput(this.input)) {
throw new CobiGenRuntimeException("An invalid input of type " + this.input.getClass() + " has been passed to " + inputReader.getClass() + " (derived from trigger '" + trigger.getId() + "')");
}
List<Object> inputObjects = this.inputResolver.resolveContainerElements(this.input, trigger);
TemplatesConfiguration tConfig = this.configurationHolder.readTemplatesConfiguration(trigger);
String templateEngineName = tConfig.getTemplateEngine();
TextTemplateEngine templateEngine = TemplateEngineRegistry.getEngine(templateEngineName);
templateEngine.setTemplateFolder(this.configurationHolder.readContextConfiguration().getConfigurationPath().resolve(trigger.getTemplateFolder()));
Template templateEty = tConfig.getTemplate(template.getId());
if (templateEty == null) {
throw new UnknownTemplateException(template.getId());
}
for (Object generatorInput : inputObjects) {
progressCallback.accept("Building template model for input " + generatorInput, 1);
Map<String, Object> model = buildModel(triggerInterpreter, trigger, generatorInput, templateEty);
String targetCharset = templateEty.getTargetCharset();
// resolve temporary file paths
@SuppressWarnings("unchecked") PathExpressionResolver pathExpressionResolver = new PathExpressionResolver(Variables.fromMap((Map<String, String>) model.get(ModelBuilderImpl.NS_VARIABLES)));
String resolvedTargetDestinationPath = pathExpressionResolver.evaluateExpressions(templateEty.getUnresolvedTargetPath());
String resolvedTmpDestinationPath = pathExpressionResolver.evaluateExpressions(templateEty.getUnresolvedTemplatePath());
File originalFile = this.targetRootPath.resolve(resolvedTargetDestinationPath).toFile();
File tmpOriginalFile;
if (origToTmpFileTrace.containsKey(originalFile)) {
// use the available temporary file
tmpOriginalFile = origToTmpFileTrace.get(originalFile);
} else {
tmpOriginalFile = this.tmpTargetRootPath.resolve(resolvedTmpDestinationPath).toFile();
// remember mapping to later on copy the generated resources to its target destinations
origToTmpFileTrace.put(originalFile, tmpOriginalFile);
}
if (originalFile.exists() || tmpOriginalFile.exists()) {
if (!tmpOriginalFile.exists()) {
try {
FileUtils.copyFile(originalFile, tmpOriginalFile);
} catch (IOException e) {
throw new CobiGenRuntimeException("Could not copy file " + originalFile.getPath() + " to tmp generation directory! Generation skipped.", e);
}
}
if ((this.forceOverride || template.isForceOverride()) && templateEty.getMergeStrategy() == null || ConfigurationConstants.MERGE_STRATEGY_OVERRIDE.equals(templateEty.getMergeStrategy())) {
try (Formatter formatter = new Formatter()) {
formatter.format("Overriding %1$-40s FROM %2$-50s TO %3$s ...", originalFile.getName(), templateEty.getName(), resolvedTargetDestinationPath);
LOG.info(formatter.out().toString());
progressCallback.accept(formatter.out().toString(), 1);
}
progressCallback.accept("Generating " + template.getId() + " for " + generatorInput, 1);
generateTemplateAndWriteFile(tmpOriginalFile, templateEty, templateEngine, model, targetCharset);
} else if (templateEty.getMergeStrategy() != null) {
try (Formatter formatter = new Formatter()) {
formatter.format("Merging %1$-40s FROM %2$-50s TO %3$s ...", originalFile.getName(), templateEty.getName(), resolvedTargetDestinationPath);
LOG.info(formatter.out().toString());
progressCallback.accept(formatter.out().toString(), 1);
}
String patch = null;
try (Writer out = new StringWriter()) {
templateEngine.process(templateEty, model, out, targetCharset);
patch = out.toString();
String mergeResult = null;
Merger merger = PluginRegistry.getMerger(templateEty.getMergeStrategy());
if (merger != null) {
mergeResult = merger.merge(tmpOriginalFile, patch, targetCharset);
} else {
throw new PluginNotAvailableException("merge strategy '" + templateEty.getMergeStrategy() + "'", null);
}
if (mergeResult != null) {
LOG.debug("Merge {} with char set {}.", tmpOriginalFile.getName(), targetCharset);
FileUtils.writeStringToFile(tmpOriginalFile, mergeResult, targetCharset);
} else {
throw new PluginProcessingException("Merger " + merger.getType() + " returned null on merge(...), which is not allowed.");
}
} catch (MergeException e) {
writeBrokenPatchFile(targetCharset, tmpOriginalFile, patch);
// enrich merge exception to provide template ID
throw new MergeException(e, templateEty.getAbsoluteTemplatePath());
} catch (IOException e) {
throw new CobiGenRuntimeException("Could not write file " + tmpOriginalFile.toPath() + " after merge.", e);
}
}
} else {
try (Formatter formatter = new Formatter()) {
formatter.format("Generating %1$-40s FROM %2$-50s TO %3$s ...", originalFile.getName(), templateEty.getName(), resolvedTargetDestinationPath);
LOG.info(formatter.out().toString());
progressCallback.accept(formatter.out().toString(), 1);
}
generateTemplateAndWriteFile(tmpOriginalFile, templateEty, templateEngine, model, targetCharset);
}
}
}
Aggregations