The easiest way to benefit from incremental generation is to use the IncrementalGenerationFacade workflow component:
<workflow> <component id="incremental" class="org.eclipse.xpand2.incremental.IncrementalGenerationFacade"> <newModelFile value="path/to/your/model.file" /> <oldModelFile value="path/to/backup/model.file" /> <traceModelFile value="path/to/store/trace/model.trace" /> <outlet path="path/to/your/outlet/" overwrite="true"/> </component> <component id="generator" class="org.eclipse.xpand2.Generator"> <expand value="your::template::Root FOR model" /> <outlet path="temp/" overwrite="true"/> <metaModel class="org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel" /> <vetoableCallback idRef="incremental" /> </component> </workflow>
The IncrementalGenerationFacade takes four parameters:
The newModelFile is the file path where the model to generate is stored. This file is stored in a model slot named model
The oldModelFile is the file path where a copy of the previous state of the model is stored. The model is automatically copied to this location after the generation process and kept between generator invocations.
The traceModelFile is the file path where the trace model of the generation process is stored between generator invocations.
A regular outlet list that must match the one given for the regular generator invocation.
The IncrementalGenerationFacade component must then be passed as a vetoableCallback parameter to the invocation of the Xpand Generator .
With the simple workflow given above, you should be able to observe that for any given change in the model, only the files affected by that change are regenerated, while all others remain untouched. Even deleting elements will result in specific (previously generated) files being deleted from the hard disk.
Note that you have to use file paths for all models because they are physically copied on the hard disk. Passing locations that can only be resolved from the classpath is not possible.
While the IncrementalGenerationFacade is easy to use, it is rather restricted in its capabilities and fixed in the operations it performs. Using the IncrementalGenerationCallback gives you more control over the steps involved. A typical workflow for incremental generation needs to perform the following tasks:
Read the (current) model into a slot.
Read the previous state of the model into another slot. This may, of course, not exist, e.g. for the very first invocation. Full generation must be performed in this case.
Compute the changes between the two versions of the model (if possible) and put that diff model into a slot.
Read the trace model computed during the previous generator invocation and put it into a slot. As with the old state of the model, this may not exist, which also leads to full generation.
Initialize the IncrementalGenerationCallback with the diff model and the trace model .
Run the Xpand Generator component with the IncrementalGenerationCallback .
Clean obsolete files, i.e. files that need to be deleted because the corresponding elements in the model have been deleted.
Write the new trace model computed during code generation to the hard disk so that it is available for the next generation process.
Make a backup copy of the model so that it can be compared with the next version upon subsequent generator invocation.
This is a sample workflow that performs all these steps:
<workflow> <!-- read new model --> <component id="modelreader" class="org.eclipse.emf.mwe.utils.Reader" uri="model/my.model" firstElementOnly="true" modelSlot="model" /> <!-- read old model, copied from previous run. may not exist, so ignore missing model --> <component id="oldmodelreader" class="org.eclipse.emf.mwe.utils.Reader" uri="temp/old.model" firstElementOnly="true" ignoreMissingModel="true" modelSlot="oldmodel" /> <!-- compute diff. --> <component id="compare" class="org.eclipse.xpand2.incremental.compare.EmfCompare" oldModelSlot="oldmodel" newModelSlot="model" diffModelSlot="diff" /> <!-- read trace model, produced by previous run. may not exist, so ignore missing model --> <component id="tracemodelreader" class="org.eclipse.emf.mwe.utils.Reader" uri="temp/trace.trace" firstElementOnly="true" ignoreMissingModel="true" modelSlot="oldtrace" /> <!-- this is the actual incremental generation callback --> <component id="incremental" class="org.eclipse.xpand2.incremental.IncrementalGenerationCallback" diffModelSlot="diff" oldTraceModelSlot="oldtrace" newTraceModelSlot="trace" /> <!-- generate code --> <component id="generator" class="org.eclipse.xpand2.Generator"> <expand value="resources::templates::Test::Test FOR model" /> <outlet path="somewhere/" overwrite="true"/> <metaModel class="org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel" /> <vetoableCallback idRef="incremental" /> </component> <!-- clean obsolete files --> <component id="cleaner" class="org.eclipse.xpand2.incremental.FileCleaner"> <oldTraceModelSlot value="oldtrace" /> <newTraceModelSlot value="trace" /> <outlet path="somewhere/" overwrite="true"/> </component> <!-- write trace model --> <component id="tracemodelwriter" class="org.eclipse.emf.mwe.utils.Writer" modelSlot="trace" uri="temp/trace.trace" /> <!-- make backup copy of model --> <component id="copier" class="org.eclipse.emf.mwe.utils.FileCopy" sourceFile="model/my.model" targetFile="temp/old.model" /> </workflow>