Open
Description
Pre and post action support when invoking a template?
Is it feasible for the template system to do some post actions after invoking a template? Or is this out of scope of the design?
I am doing cmdlet development in F# and when invoking a F# source file template I would like the F# source file to be added to the F# project.
I have created a prototype implementation to be added to the function Invoke-PSMDTemplate, sub function Write-TemplateItem. It is probably not the ideal place to put such implementation? General support for pre-action script and post-action script would probably be better? At least I have something that works on my dev machine for the time being.
Write-TemplateItem (changed from approx line 342):
[...]
[System.IO.File]::WriteAllText($destPath, $text, $Encoding)
#Start: Support for adding *fs file to F# project
#If destination path is a *.fs file it should to be included in a F# project in the current directory
#or some parent directory futher up. Look for the neares .*fsproj file and add the file to the project.
if($destPath.EndsWith(".fs"))
{
#Destination is a F# source file. Find the parent project(s) and add.
$destinationFile = [System.IO.FileInfo]::new($destPath)
Find-PsmdFsProject -FolderPath $($destinationFile.Directory.FullName) | ForEach-Object {
$fsProjectFilePath = $_
Add-PSMDFsFileToFsProject -FsFilePath $destPath -FsProjectPath $fsProjectFilePath
}
}
#End: Support for adding *fs file to F# project
[...]
The implementation of the functions Find-PsmdFsProject and Add-PSMDFsFileToFsProject follows:
Find-PsmdFsProject
function Find-PsmdFsProject
{
<#
.SYNOPSIS
Find F# nearest project file(s) in current directory or in parent directories.
.DESCRIPTION
Find F# nearest project file(s) in current directory or in parent directories.
.PARAMETER FolderPath
Full path to the folder to search
.EXAMPLE
Write-Host Find neares F# project file.
Find-PsmdFsProject -FolderPath "C:\temp\Fsharp.Console.TestApp\Tests"
.NOTES
Version: 1.0
Author: github/trondr
Company: github/trondr
Repository: https://github.com/trondr/PSModuleDevelopment.git
#>
param(
[ValidateScript({ (Test-Path $_ -PathType 'Container') })]
[string]
$FolderPath
)
$projectFiles = Get-ChildItem -LiteralPath $FolderPath -Filter "*.fsproj" -File
if($projectFiles.Length -eq 0)
{
#Did not find *.fsproj file(s) in current directory, continue recursively up the tree.
$Directory = [System.IO.DirectoryInfo]::new($FolderPath)
if($null -ne $Directory.Parent)
{
Find-PsmdFsProject -FolderPath $($Directory.Parent.FullName)
}
}
else {
#Found *.fsproj file(s) in current directory, stop the search and return the findings.
$projectFiles | ForEach-Object{ Write-Output -InputObject $_.FullName}
}
}
Add-PSMDFsFileToFsProject
function Add-PsmdFsFileToFsProject {
<#
.SYNOPSIS
Adds a f# source file to a F# project.
.DESCRIPTION
Adds a f# source file to a F# project. Source file is inserted before Program.fs
if project is a console project. Otherwise source file is added to the end.
.PARAMETER FsProjectPath
Full path to the F# project file.
.PARAMETER FsFilePath
Full path to the F# source file.
.EXAMPLE
Write-Host Add F# source file to F# project
$fsprojectFilePath = "C:\temp\Fsharp.Console.TestApp\Fsharp.Console.TestApp.fsproj"
$fsFilePath = "C:\temp\Fsharp.Console.TestApp\Tests\ExampleTests2.fs"
Add-PSMDFsFileToFsProject -FsProjectPath $fsprojectFilePath -FsFilePath $fsFilePath
.NOTES
Version: 1.0
Author: github/trondr
Company: github/trondr
Repository: https://github.com/trondr/PSModuleDevelopment.git
#>
[CmdletBinding()]
param (
[ValidateScript({
[string]$path = $_
(Test-Path $path -PathType 'Leaf') -and ($path.EndsWith(".fsproj"))
})]
[string]
$FsProjectPath,
[ValidateScript({
[string]$path = $_
(Test-Path $path -PathType 'Leaf') -and ($path.EndsWith(".fs"))
})]
[string]
$FsFilePath
)
begin {
$fsProjectFileDirectoryPath = [System.IO.FileInfo]::new($FsProjectPath).Directory.FullName
$fsFilePathRelativePath = $FsFilePath.Replace($fsProjectFileDirectoryPath,"").TrimStart([System.IO.Path]::DirectorySeparatorChar).Replace([System.IO.Path]::DirectorySeparatorChar,[System.IO.Path]::AltDirectorySeparatorChar)
function Format-XML
{
param(
[xml]$Xml,
$Indent=2
)
$StringWriter = New-Object System.IO.StringWriter
$XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter
$xmlWriter.Formatting = "indented"
$xmlWriter.Indentation = $Indent
$xml.WriteContentTo($XmlWriter)| Out-Null
$XmlWriter.Flush()
$StringWriter.Flush()
Write-Output $StringWriter.ToString()
}
}
process {
[xml]$fsprojXmlDoc = Get-Content $FsProjectPath
$itemGroups = $fsprojXmlDoc.SelectNodes("/Project/ItemGroup/Compile")
if($itemGroups.Count -gt 0)
{
$allreadyExists = (($itemGroups.Include | Where-Object { ($_ -eq $fsFilePathRelativePath) }) | Measure-Object).Count -gt 0
if($allreadyExists -eq $false)
{
#Fs file is not allready added, so add it.
Write-Host "Adding file '$FsFilePath' to project '$FsProjectPath'." -ForegroundColor Green
[System.Xml.XmlNode]$compileElement = $fsprojXmlDoc.CreateElement("Compile")
($compileElement.SetAttribute("Include",$fsFilePathRelativePath)) | Out-Null
[System.Xml.XmlNode]$parentNode = $itemGroups[0].ParentNode
[System.Xml.XmlNode]$lastChild = $parentNode.LastChild
if ($parentNode.LastChild.Include -ieq "Program.fs")
{
#Add the new Compile item before Program.fs).
($parentNode.InsertBefore($compileElement, $lastChild)) | Out-Null
}
else {
#Add the new Compile item to the end of the list.
($parentNode.AppendChild($compileElement)) | Out-Null
}
#Write changes back to fsproj file.
(Format-XML -Xml $($fsprojXmlDoc.InnerXml) -Indent 4) | Set-Content -Path $fsprojectFilePath -Encoding utf8BOM | Out-Null
}
else {
Write-Host "File '$FsFilePath' has allready been added to project '$FsProjectPath'." -ForegroundColor Yellow
}
}
else {
Write-Host "No ItemGroup with Compile items found in project file '$FsProjectPath'. There must be at least one Compile item in one ItemGroup." -ForegroundColor Yellow
}
}
end {
}
}