2012-12-10 10 views
6

Próbuję uruchomić nasze szablony T4 w czasie kompilacji, bez dodawania zależności w pakiecie Visual Studio Modeling SDK. Z powodzeniem użyłem wariantu pliku wsadowego pokazanego jako here, ale mam teraz problem polegający na tym, że moje pliki .tt używają zmiennej $(SolutionDir) do odwoływania się do innych projektów (a zatem nie są teraz kompilowane).

Jaki jest najlepszy sposób na radzenie sobie z tym? Co zrobili inni ludzie? (Hard kodowania ścieżek bezwzględnych nie jest opcją)

EDIT: widzę tam jest -a argument, że mogą być przekazywane do TextTransform.exe, jest to możliwe, aby to wykorzystać do określenia $(SolutionDir)?

+1

Możesz próbowano ustawić SolutionDir '=% CD%' ustawić zmienną do bieżącego katalogu? – Pawel

+1

To nie działa, nie ma również -a !! $ (SolutionDir)! C: \ dev \ mysolutionroot – piers7

+0

Istnieje jeden port Mono T4. Zastanawiam się, czy odpowiedź jest gdzieś w bazie kodu. Zobacz http://stackoverflow.com/a/1395377/26167 – piers7

Odpowiedz

2

Przeglądanie kodu źródłowego z TextTransformation.exe (z ILSpy) Nie sądzę, że jest to możliwe bez modyfikacji szablonu (ale mam rozwiązanie).

Ostatecznie co dbamy o tutaj jest krokiem podczas parsowania szablonu gdzie Microsoft.VisualStudio.TextTemplating.Engine.ResolveAssemblyReferences() nazywa. Ten delegatów ITextTemplatingEngineHost.ResolveAssemblyReference() (chociaż to robi pierwsze zmienne środowiskowe)

Gdy szablon jest uruchamiany z linii poleceń, realizacja używany, że dostarczone przez CommandLineHost, a jego realizacja po prostu szuka pliku w postaci dostarczonej w ścieżkach referencyjnych i GAC. Biorąc pod uwagę, że nazwa pliku będzie nadal zawierać bit $ (SolutionPath), nigdy się to nie uda.

Można zaimplementować własne wersję TextTransform.exe, ale trzeba by zacząć w dużej mierze od zera (lub użyć refleksji), ponieważ CommandLineHost jest wewnętrzny :-(Albo można potencjalnie wykorzystać port Mono https://stackoverflow.com/a/1395377/26167

nie mogę powiedzieć, że jestem zadowolony z tego, bo znajdę się w tej samej łodzi ...

Edit: jednak ... ponieważ ostatecznie wszystko, co trzeba zrobić, to zmienić szablon, Przygotowałem skrypt PowerShell do skopiowania szablonów do katalogu temp, ręcznie rozszerzając $ (SolutionDir) ma cro w tym procesie, i wykonuj je stamtąd. To wydaje się działać po prostu dobrze.

Kropla to do projektu naruszającego (może chcesz zmienić rozszerzenie pliku) i powinno być dobrze iść:

<# 
.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; 
} 
+0

Czy mógłbyś to trochę rozwinąć - gdzie "rzucił" to do projektu? Czy po prostu zadzwonisz do tego z operacji przed lub po kompilacji? –

+0

Kod zapisany zakłada, że ​​katalog rozwiązań jest jednym folderem w górę i znajduje pliki TT względem siebie. Dodaj go do projektu w katalogu głównym. Można to wykonać z wiersza poleceń (w PowerShell), i tak - prawdopodobnie można wywołać to w etapie wstępnej kompilacji, jeśli zajdzie taka potrzeba (robię to ręcznie). – piers7

+0

@ piers7 Dzięki za udostępnienie. Zastąpiłem twoje stałe rozszerzenie pliku rozszerzeniem wyodrębnionym z samego pliku tt za pomocą wyrażeń regularnych ... '$ extension = Select-String -Path $ template.FullName -Pattern '<# @ \ s * output \ s + extension = "(. *)" \ s * #> "| ForEach-Object {$ _. Matches.Groups [1] .Value} ' – Hosein

0

Kiedyś podejście bardzo podobny do piers7 - chyba w moim przypadku, Właściwie to musiałem przechowywać plik * .tt w tym samym katalogu (z powodu wyszukiwania plików na podstawie względnych ścieżek), ale nie obchodziło mnie, czy sam plik miał inną nazwę. Zamiast tego, zamiast $ templateTemp utworzyć tymczasowy plik w katalogu tymczasowym, zachowałem go w tym samym folderze.

Potrzebowałem również rekursywnie wyszukiwać pliki * .tt w dowolnym miejscu w katalogu rozwiązania.

Oto otrzymany scenariusz, biorąc piers7 i modyfikując go:

<# 
.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; 
} 
Powiązane problemy