You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 {
}
}
The text was updated successfully, but these errors were encountered:
Heya,
thank for the suggestion!
Technically it's out of the scope of the system ... to be f# specific.
What is in-scope however is an extended support for integrated logic:
Currently, scriptblocks are all executed at the beginning of the entire template (not the specific file they may be assigned to).
The new version is going to support:
Start Script (before starting template)
Pre-File script
Post-File script
End Script (once template is done)
Actually, the object model has already been updated, however I have yet to integrate it into the commands.
It's definitely the number 1 feature on my dev list for the next version.
Could be a nifty idea to also support some kind of building-block system - template fragments? - that can be reused in multiple templates.
Or templates directly referencing templates ...
Anyway, future ramblings, the scriptblock updates are definitely coming soon(tm)
Thanks! Looking forward to the new version! From what you are saying I understand that in the new version I will be able to move any F# specific code to a start/post/pre script block in the specific F# template. Instead of hardcoding support for F# in the main engine like I did in the prototype. Using start/pre/post script seems much cleaner!
By the way will there be any context provided to the script blocks? Such as $outpath? And other parameter values?
I guess access to variables via Get-PSFConfig will allways be availble, but maybe script blocks could be resolved before execution so that any variables on the format þsomevariableþ in the script are expanded before script execution? This can possibly simplify coding of script blocks somewhat. But the same information could also be stored in an easy accessible context variable that the the script can extract on execution.
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):
The implementation of the functions Find-PsmdFsProject and Add-PSMDFsFileToFsProject follows:
Find-PsmdFsProject
Add-PSMDFsFileToFsProject
The text was updated successfully, but these errors were encountered: