Introduction
We have being developed a ReSharper plugin for Catel framework also known as CatelR# for a while, following an interesting approach in order support the new R# version and also keep the backward compatibility.
If you want to know how we made it, just take a look.
Visual Studio solution setup
1) Create project per supported R# version, which means that the output of each project is targeting to the specific version of R# and references the specific version of the SDK.
2) Keep in mind, that could be several breaking changes between R# SDK versions, but nothing that couldn’t be handled with pre-processor directives.
#if R70 || R71 || R80 protected override void Process(CSharpGeneratorContext context) #elif R61 public override void Process(CSharpGeneratorContext context) #endif { CSharpElementFactory factory = CSharpElementFactory.GetInstance(context.Root.GetPsiModule()); #if R80 IDeclaredType viewModelToModelAttributeClrType = TypeFactory.CreateTypeByCLRName(CatelMVVM.ViewModelToModelAttribute, context.PsiModule, UniversalModuleReferenceContext.Instance); #else IDeclaredType viewModelToModelAttributeClrType = TypeFactory.CreateTypeByCLRName(CatelMVVM.ViewModelToModelAttribute, context.PsiModule); #endif /*...*/ #if R80 var fixedArguments = new List<AttributeValue> { new AttributeValue(ClrConstantValueFactory.CreateStringValue(model.ShortName, context.PsiModule, UniversalModuleReferenceContext.Instance)) }; #else var fixedArguments = new List<AttributeValue> { new AttributeValue(ClrConstantValueFactory.CreateStringValue(model.ShortName, context.PsiModule)) }; #endif if (propertyName != modelProperty.ShortName) { #if R80 fixedArguments.Add(new AttributeValue(ClrConstantValueFactory.CreateStringValue(modelProperty.ShortName, context.PsiModule, UniversalModuleReferenceContext.Instance))); #else fixedArguments.Add(new AttributeValue(ClrConstantValueFactory.CreateStringValue(modelProperty.ShortName, context.PsiModule))); #endif } /*...*/ } } } }
3) Keep all these entire project sources synchronized. Could be very easy thanks to Caitlyn.
4) Finally redirect the build projects outputs to dealing with ease with the packaging of the deployment units.
Building the deployment units
The R# plugin build process indeed an heterogeneous one as any build process. Even though this build could be handled via msbuild tasks, we actually recommend the usage of tools with intuitive GUI in order to quickly creating and debugging such build "scripts", such as FinalBuilder or VisualBuild.
1) Since 8.0 R# version the NuGet based extension manager is available. Therefore one of the build output could be a NuGet package to distribute your plugin through the ReSharper extension gallery.
2) But NuGet based extension manager is not available for all R# versions. Therefore a second build output could also be classic deployment unit built on top of any of the existing installer system. For instance InnoSetup or NSIS.
The following are the code snippets from the install and uninstall sections of CatelR# setup. Notice how we deal with build output to support all R# versions.
# ... # Installer section # ... Push "v6.1" Push "v7.0" Push "v7.1" Push "v8.0" Push "v8.1" ${Do} Pop $0 ReadRegStr $1 HKLM "Software\JetBrains\ReSharper\$0" InstallDir ${If} $1 != '' DetailPrint "Installing Catel.ReSharper for JetBrains ReSharper $0" SetOutPath "$1\Plugins\$(^Name)" ${If} $0 == 'v6.1' File /r "..\..\output\Debug\v6.1\*.dll" ${ElseIf} $0 == 'v7.0' File /r "..\..\output\Debug\v7.0\*.dll" ${ElseIf} $0 == 'v7.1' File /r "..\..\output\Debug\v7.1\*.dll" ${ElseIf} $0 == 'v8.0' File /r "..\..\output\Debug\v8.0\*.dll" ${ElseIf} $0 == 'v8.1' File /r "..\..\output\Debug\v8.1\*.dll" ${EndIf} Push true Pop $3 WriteRegStr HKLM "${REGKEY}" "$0" 1 ${EndIf} ${LoopUntil} $0 == "v6.1" # ... # ... # Uninstaller section # ... Push "v6.1" Push "v7.0" Push "v7.1" Push "v8.0" Push "v8.1" ${Do} Pop $0 ReadRegStr $1 HKLM "${REGKEY}" "$0" ${If} $1 == '1' ReadRegStr $2 HKLM "Software\JetBrains\ReSharper\$0" InstallDir ${If} $2 != '' RMDir /r /REBOOTOK "$2\Plugins\$(^Name)" DeleteRegValue HKLM "${REGKEY}" "$0" ${EndIf} ${EndIf} ${LoopUntil} $0 == "v6.1" # ...
Conclusions
Just a few minutes ago, I read the notification about the release of R#8.2 EAP. It’s a good moment to revalidate this approach. Let’s see,… creating a new project with post-fix 82, …installing the SDK package, ..., ...time out, sorry…slow connection…,…,…,..updating the build script, …, …, … reviewing for breaking changes, good news, there are no breaking changes,… updating setup script…., committing source modifications, … running the build script and it’s done.
Now you can update the extension from the extension gallery or download the full installer of CatelR# with support for R#8.2 EAP ;)