Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add F# source file to F# project when invoking a F# source file template? #162

Copy link
Copy link
@trondr

Description

@trondr
Issue body actions

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 {
        
    }
}
Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.