Reputation: 3631
I'm trying to add a saved file to the current project of my T4 template file.
The file is saved as expected by the SaveOutput
method, but when I use the IncludeInCurrentProject
method, that calls the ProjectItems.AddFromFile
(docs here), and then the file is added on the root of the project.
I'd like to include the file generated by the SaveOutput
method on that exactly location on the project.
This is what I have right now:
Here is my .tt file:
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".sql" #>
<#@ assembly name="Microsoft.VisualBasic.dll" #>
<#@ assembly name="EnvDTE" #>
<#@ import Namespace="System.IO" #>
<#@ import namespace="EnvDTE" #>
<#
var MigrationName = Microsoft.VisualBasic.Interaction.InputBox("InputBox Label", "Description");
if (string.IsNullOrWhiteSpace(MigrationName))
return "";
var MigrationVersion = System.DateTime.Now.ToString("yyyyMMddHHmm");
var MigrationFileName = MigrationVersion + "-" + MigrationName + ".sql";
var MigrationFilePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Host.TemplateFile), "", MigrationFileName));
#>
My T4 template goes here
<#
SaveOutput(MigrationFilePath);
IncludeInCurrentProject(MigrationFilePath)
.Open(Constants.vsViewKindPrimary)
.Activate();
#>
<#+
private void SaveOutput(string filename)
{
File.WriteAllText(filename, GenerationEnvironment.ToString());
GenerationEnvironment.Clear();
}
private ProjectItem IncludeInCurrentProject(string filename)
{
return CurrentProject.ProjectItems.AddFromFile(filename);
}
private Project CurrentProject
{
get
{
if (_currentProject == null) {
var serviceProvider = (IServiceProvider)this.Host;
var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
foreach(Project project in dte.Solution.Projects)
{
// workaround. dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject didn't work
string projectPath = project.FullName.Replace("\\" + project.FileName, string.Empty);
if(Host.TemplateFile.Contains(projectPath))
{
_currentProject = project;
break;
}
}
}
return _currentProject;
}
}
private Project _currentProject;
#>
How can I include my generated files on the same folder of the T4 template file?
Upvotes: 2
Views: 699
Reputation: 3631
The CurrentProject.ProjectItems
always references the ProjectItems
in the root.
I used the file path to navigate through the ProjectItems
and call the AddFromFile
on the correct one. You can check the GetCurrentProjectItem
method, this behaviour is implemented there.
Now the template works fine:
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".sql" #>
<#@ assembly name="Microsoft.VisualBasic.dll" #>
<#@ assembly name="EnvDTE" #>
<#@ import Namespace="System.IO" #>
<#@ import Namespace="System.Text.RegularExpressions" #>
<#@ import namespace="EnvDTE" #>
<#
var migrationName = Microsoft.VisualBasic.Interaction.InputBox("InputBox Label", "Description");
Regex alphaNumericRegex = new Regex("[^a-zA-Z0-9-_]");
migrationName = alphaNumericRegex.Replace(migrationName, string.Empty);
if (string.IsNullOrWhiteSpace(migrationName))
return "";
var migrationVersion = System.DateTime.Now.ToString("yyyyMMddHHmm");
var migrationFileName = migrationVersion + "-InsertCourt" + migrationName + ".sql";
var migrationFilePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Host.TemplateFile), migrationFileName));
#>
My T4 template goes here
<#
SaveOutput(migrationFilePath);
IncludeInCurrentProject(migrationFilePath)
.Open(Constants.vsViewKindPrimary)
.Activate();
#>
<#+
private void SaveOutput(string filename)
{
File.WriteAllText(filename, GenerationEnvironment.ToString());
GenerationEnvironment.Clear();
}
private ProjectItem IncludeInCurrentProject(string filename)
{
ProjectItem item = GetCurrentProjectItem().ProjectItems.AddFromFile(filename);
item.Properties.Item("BuildAction").Value = "None";
return item;
}
private ProjectItem GetCurrentProjectItem()
{
var serviceProvider = (IServiceProvider)this.Host;
var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
string templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
string foldersString = templateDirectory.Replace(Path.GetDirectoryName(GetCurrentProject().FullName), string.Empty);
string[] foldersArray = foldersString.Split(new [] {"\\"}, StringSplitOptions.RemoveEmptyEntries);
foreach(Project project in dte.Solution.Projects)
{
ProjectItems currentProjectItems = null;
foreach(string folder in foldersArray)
{
if(currentProjectItems == null)
{
currentProjectItems = project.ProjectItems;
}
foreach(ProjectItem projectItem in currentProjectItems)
{
if(projectItem.Name == folder)
{
if(Array.IndexOf(foldersArray, folder) == foldersArray.Length - 1)
{
return projectItem;
}
currentProjectItems = projectItem.ProjectItems;
break;
}
}
}
}
return null;
}
private Project GetCurrentProject()
{
var serviceProvider = (IServiceProvider)this.Host;
var dte = serviceProvider.GetService(typeof(DTE)) as DTE;
foreach(Project project in dte.Solution.Projects)
{
// workaround. dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject didn't work
string directory = Path.GetDirectoryName(project.FullName);
if(Host.TemplateFile.Contains(directory))
{
return project;
}
}
return null;
}
private ProjectItem _currentProjectItem;
#>
Upvotes: 1
Reputation: 263
When you call the IncludeInCurrentProject the input should be the path + filename.
Upvotes: 0