Using $ (SolutionDir) when starting a template through TextTransform.exe

I am trying to run our T4 templates at build time without adding a dependency on the Visual Studio Modeling SDK. I have successfully used the batch file option shown here , but now I have a problem in that my .tt files use the $(SolutionDir) variable to reference other projects (and therefore are not compiled now).

What is the best way to handle this? What did other people do? (Absolute hardcoding paths are not an option)

EDIT: I see there the -a argument that can be passed to TextTransform.exe, can this be used to define $(SolutionDir) ?

+6
source share
2 answers

Looking through the source code from TextTransformation.exe (using ILSpy), I do not think that this is possible without changing the template (but I have a solution).

Ultimately, we take care of this step while parsing the template where Microsoft.VisualStudio.TextTemplating.Engine.ResolveAssemblyReferences () is called. This delegates to ITextTemplatingEngineHost.ResolveAssemblyReference () (although it expands environment variables first)

When the template is launched from the command line, the implementation used is executed using CommandLineHost , and its implementation simply looks for the file specified in the reference paths and in the GAC. Given that the file name at this point will still contain the $ (SolutionPath) bit, it will never succeed.

You can implement your own version of TextTransform.exe, but you will have to start mostly from scratch (or use reflection), because CommandLineHost is internal :-( Or you can potentially use the mono port fooobar.com/questions/31146 / ...

I can’t say that I am pleased with this because I ended up in the same boat ...

Edit: However, since ultimately all you have to do is change the template, I put together a PowerShell script to copy the templates to the temp directory, manually expanding $ (SolutionDir) in the process and executing them from there. Everything seems to be working fine.

Drop this into an offensive project (you might want to change the file extension), and you should be fine:

 <# .Synopsis Executes all the T4 templates within designated areas of the containing project .Description Unfortunately the Visual Studio 2010 'Transform All Templates' function doesn't appear to work in SSDT projects, so have to resort to hackery like this to bulk-execute templates #> param( ) $ErrorActionPreference = 'stop'; $scriptDir = Split-Path $MyInvocation.MyCommand.Path $commonProgramFiles32 = $env:CommmonProgramFiles if (Test-Path environment::"CommonProgramFiles(x86)") { $commonProgramFiles32 = (gi "Env:CommonProgramFiles(x86)").Value }; $t4 = Resolve-Path "$commonProgramFiles32\Microsoft Shared\TextTemplating\10.0\texttransform.exe"; $solutionDir = Resolve-Path "$scriptDir\..\" $templates = @(dir "$scriptDir\Database Objects\load\*.tt") # Cloning to temp dir originally caused issues, because I use the file name in the template (doh!) # Now I copy to temp dir under the same name pushd $scriptDir; try{ foreach($template in $templates){ $templateTemp = Join-Path ([IO.Path]::GetTempPath()) $template.Name; $targetfile = [IO.Path]::ChangeExtension($template.FullName, '.sql'); Write-Host "Running $($template.Name)" Write-Host "...output to $targetFile"; # When run from outside VisualStudio you can't use $(SolutionDir) # ...so have to modify the template to get this to work... # ...do this by cloning to a temp file, and running this instead Get-Content $template.FullName | % { $_.Replace('$(SolutionDir)',"$solutionDir") } | Out-File -FilePath:$templateTemp try{ & $t4 $templateTemp -out $targetfile -I $template.DirectoryName; }finally{ if(Test-Path $templateTemp){ Remove-Item $templateTemp; } } } }finally{ popd; } 
+2
source

I used an approach very similar to piers7 - except for my case, I really needed to save the * .tt file in the same directory (due to search in runtime files based on relative paths), but still if the file itself was named differently. Thus, instead of having $ templateTemp, create a temporary file in the temp directory, I saved it in the same folder.

I also needed to recursively search for * .tt files anywhere in the solution directory.

Here is the result of the script, taking piers7 and changing it:

 <# .Synopsis Executes all the T4 templates within designated areas of the containing project #> param( ) $ErrorActionPreference = 'stop'; $scriptDir = Split-Path $MyInvocation.MyCommand.Path $commonProgramFiles32 = $env:CommmonProgramFiles if (Test-Path environment::"CommonProgramFiles(x86)") { $commonProgramFiles32 = (gi "Env:CommonProgramFiles(x86)").Value }; $t4 = Resolve-Path "$commonProgramFiles32\Microsoft Shared\TextTemplating\12.0\texttransform.exe"; $solutionDir = Resolve-Path "$scriptDir\" $templates = Get-ChildItem -Path $scriptDir -Filter *.tt -Recurse $extension = '.ts'; pushd $scriptDir; try{ foreach($template in $templates){ # keeping the same path (because my template references relative paths), # but copying under different name: $templateTemp = $template.FullName + "____temporary" $targetfile = [IO.Path]::ChangeExtension($template.FullName, $extension); Write-Host "Running $($template.Name)" Write-Host "...output to $targetFile"; # When run from outside VisualStudio you can't use $(SolutionDir) # ...so have to modify the template to get this to work... # ...do this by cloning to a temp file, and running this instead Get-Content $template.FullName | % { $_.Replace('$(SolutionDir)',"$solutionDir") } | Out-File -FilePath:$templateTemp try{ & $t4 $templateTemp -out $targetfile -I $template.DirectoryName; }finally{ if(Test-Path $templateTemp){ Remove-Item $templateTemp; } } } }finally{ popd; } 
0
source

All Articles