8

Visual Studio Modeling SDK への依存関係を追加せずに、ビルド時に T4 テンプレートを実行しようとしています。ここに示されているバッチ ファイルのバリアントを正常に使用できましたが、.tt ファイルが$(SolutionDir)変数を使用して他のプロジェクトを参照するという問題があります (そのため、現在はコンパイルされていません)。

これを処理する最善の方法は何ですか? 他の人は何をしましたか?(絶対パスのハードコーディングはオプションではありません)

編集: -aTextTransform.exe に渡すことができる引数があるようですが、これを使用して定義することは可能$(SolutionDir)ですか?

4

3 に答える 3

4

TextTransformation.exe (ILSpy を使用) のソース コードを調べてみると、テンプレートを変更しないとこれは不可能だと思います (ただし、解決策はあります)。

ここで最終的に重要なのは、Microsoft.VisualStudio.TextTemplating.Engine.ResolveAssemblyReferences()が呼び出されるテンプレート解析中のステップです。これはITextTemplatingEngineHost.ResolveAssemblyReference()に委譲します(ただし、最初に環境変数を展開します)

テンプレートがコマンド ラインから実行される場合、使用される実装はCommandLineHostによって提供されるものであり、その実装は参照パスおよび GAC で提供されるファイルを単に検索します。この時点でファイル名にまだ $(SolutionPath) ビットが含まれているため、成功することはありません。

独自のバージョンの TextTransform.exeを実装することもできますが、CommandLineHost は内部であるため、大部分を最初から開始する (またはリフレクションを使用する) 必要があります :-( または、Mono ポートhttps://stackoverflow.com/を活用する可能性があります。 a/1395377/26167

私は同じ船に乗っているので、これについて満足しているとは言えません...

編集:ただし...最終的に必要なのはテンプレートを変更することだけなので、PowerShellスクリプトをまとめてテンプレートを一時ディレクトリにコピーし、その過程で $(SolutionDir) マクロを手動で展開し、そこから実行します. それはうまくいくようです。

これを問題のあるプロジェクトにドロップしてください (ファイル拡張子を変更したい場合があります)。

<#
.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;
}
于 2013-06-06T05:56:16.820 に答える
0

私は piers7 と非常によく似たアプローチを使用しました -- 私の場合を除いて、実際には *.tt ファイルを同じディレクトリに保持する必要がありました (相対パスに基づくファイルの実行時ルックアップのため)。それ自体は別の名前が付けられました。そのため、$templateTemp で一時ディレクトリに一時ファイルを作成する代わりに、同じフォルダーに保存しました。

また、ソリューション ディレクトリ内の任意の場所にある *.tt ファイルを再帰的に検索する必要もありました。

piers7 のスクリプトを変更して作成したスクリプトは次のとおりです。

<#
.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;
}
于 2015-01-22T21:16:53.983 に答える