2012-12-10 13 views
6

Sto cercando di ottenere i nostri modelli T4 per l'esecuzione in fase di compilazione, senza aggiungere dipendenze a SDK di Visual Studio Modeling. Ho usato con successo una variante del file batch mostrato here, ma ora ho un problema in quanto i miei file .tt usano la variabile $(SolutionDir) per fare riferimento ad altri progetti (e quindi non stanno ora compilando).

Qual è il modo migliore per gestire questo? Cosa hanno fatto gli altri? (Hard-codifica i percorsi assoluti non è un'opzione)

EDIT: vedo che c'è l'argomento -a che può essere passato a TextTransform.exe, è possibile utilizzare questo per definire $(SolutionDir)?

+1

Hai provato 'set SolutionDir =% cd%' per impostare la variabile nella directory corrente? – Pawel

+1

Questo non funziona, neanche -a !! $ (SolutionDir)! C: \ dev \ mysolutionroot – piers7

+0

C'è una porta Mono di T4. Mi chiedo se la risposta sia nella base di codice da qualche parte. Vedi http://stackoverflow.com/a/1395377/26167 – piers7

risposta

2

Guardando attraverso il codice sorgente da TextTransformation.exe (con ILSpy) non penso sia possibile senza modificare il modello (ma ho una soluzione).

In definitiva ciò che ci preoccupa qui è il passo durante l'analisi modello in cui Microsoft.VisualStudio.TextTemplating.Engine.ResolveAssemblyReferences() viene chiamato. Questo delega a ITextTemplatingEngineHost.ResolveAssemblyReference() (se lo fa espandere variabili ambiente prima)

Quando il modello viene eseguito dalla riga di comando, l'applicazione utilizzata è quella fornita dal CommandLineHost, e la sua attuazione semplicemente cerca il file come fornito nei percorsi di riferimento e nel GAC. Dato che a questo punto il nome del file avrà ancora il bit $ (SolutionPath), non avrà mai successo.

Si potrebbe implementare la propria versione di TextTransform.exe, ma che avrebbe dovuto iniziare in gran parte da zero (o usare riflessione), dal momento che è CommandLineHost :-(interna o si potrebbe sfruttare la porta Mono https://stackoverflow.com/a/1395377/26167

non posso dire che sono contento di questo, perché mi trovo nella stessa barca ...

Edit: Tuttavia ... dal momento che in ultima analisi, tutto quello che dovete fare è modificare il modello, Ho creato uno script PowerShell per copiare i modelli nella directory temporanea, espandendo manualmente il ma $ (SolutionDir) cro nel processo, ed eseguirli da lì. Quello sembra funzionare alla fine.

Goccia questo nel progetto incriminato (si potrebbe desiderare di cambiare l'estensione del file) e si dovrebbe essere pronti per partire:

<# 
.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

Potresti approfondire un po 'questo argomento: dove lo "abbandonerebbe" nel progetto? Chiameresti questo da operazioni pre o post-compilazione? –

+0

Il codice come scritto presuppone che la soluzione dir sia una cartella in su e trova i file TT relativi a se stesso. Quindi aggiungilo nel progetto alla radice. Dovresti eseguirlo dalla riga di comando (in PowerShell) e sì - probabilmente potresti chiamarlo in una fase di pre-build, se necessario (lo faccio manualmente). – piers7

+0

@ piers7 Grazie per aver condiviso. Ho sostituito l'estensione del file fisso con un'estensione estratta dal file tt stesso usando espressioni regolari ... '$ extension = Select-String -Path $ template.FullName -Pattern '<# @ \ s * output \ s + extension = "(. *)" \ s * #> '| ForEach-Object {$ _. Matches.Groups [1] .Value} ' – Hosein

0

Ho usato un approccio molto simile a piers7 - tranne che nel mio caso, In realtà avevo bisogno di mantenere il file * .tt nella stessa directory (a causa della ricerca in runtime di file basati su percorsi relativi), ma non mi importava se il file stesso era chiamato diversamente. In quanto tale, invece di avere $ templateTemp creare un file temporaneo in una directory temporanea, l'ho tenuto nella stessa cartella.

Avevo anche bisogno di cercare ricorsivamente i file * .tt da qualche parte nella directory della soluzione.

Ecco lo script risultante, prendendo piers7 e di modificarlo:

<# 
.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; 
} 
Problemi correlati