PSBuildModule.psm1


# START: source\.bootstrap.ps1
New-Alias -Name Build-ModuleProject -Value Export-PSModuleProject
New-Alias -Name Initialize-ModuleProjectDirectory -Value Initialize-PSModuleProject
# END: source\.bootstrap.ps1


# START: source\_ensureProjectDirectory.ps1
function _ensureProjectDirectory{
    param(
        [string]$ProjectPath,
        [string]$ModuleName,
        [string]$ModuleAuthor,
        [guid]$ModuleGuid = [guid]::NewGuid()
    )

    "Building project directory at '{0}'..." -f $ProjectPath | Write-Debug

    $directoryStructure = @{
        type='directory'

        children = @{
            'build.settings' = @{
                type = 'directory'

                children = @{
                    'manifest' = @{
                        type = 'directory'
                        src = "$PSScriptRoot\.assets\defaultManifest"
                        children = @{
                            author = @{
                                type = 'file'
                                content = $ModuleAuthor
                            }
                            guid = @{
                                type = 'file'
                                content = $ModuleGuid
                            }
                        }
                    }
                    'modulename' = @{
                        type='file'
                        content=$ModuleName
                    }
                }
            }
            'source' = @{
                type='directory'
            }
        }
    }

    $buildDirectory = {
        param($path, $itemSpec, $prefixLength=0)
        
        switch ($prefixLength) {
            0 {
                $itemPrefix = ""
                $infoPrefix = ""
            }

            3 {
                $itemPrefix = "|- "
                $infoPrefix = " "
            }

            default {
                $itemPrefix = "|- ".PadLeft($prefixLength + 3, " ")
                $infoPrefix = " ".PadLeft($prefixLength + 3, " ")
            }
        }

        $exists = switch ($itemSpec.type) {
            file {
                Test-Path $path -PathType Leaf
            }

            directory {
                Test-Path -Path $path -PathType Container
            }
        }

        $leaf = Split-Path $path -Leaf

        if ($exists) {
            "{0}{2} '{1}': Found!" -f $itemPrefix, $leaf, $itemSpec.type.ToUpper() | Write-Debug
        } else {
            "{0}{2} '{1}': Missing!" -f $itemPrefix, $leaf, $itemSpec.type.ToUpper() | Write-Debug
        }

        if (!$exists) {
            switch($itemSpec.type) {
                file {
                    if ($itemSpec.src) {
                        Copy-Item -Path $itemSpec.src -Destination $path
                        "{0}Copying from '{1}'" -f $infoPrefix, $itemSpec.src | Write-Debug
                    } else {
                        "{0}Creating blank file" -f $infoPrefix | Write-Debug
                        New-Item -Path $path -ItemType File | Out-Null
                    }

                    if ($itemSpec.content) {
                        "{0}Setting content to '{1}'" -f $infoPrefix, $itemSpec.content | Write-Debug
                        Set-Content -Path $path -Value $itemSpec.content
                    }
                }

                directory {
                    if ($itemSpec.src) {
                        "{0}Copying from '{1}'" -f $infoPrefix, $itemSpec.src | Write-Debug
                        Copy-Item -Path $itemSpec.src -Destination $path -Recurse
                    } else {
                        "{0}Creating empty directory" -f $infoPrefix | Write-Debug
                        New-Item -Path $path -ItemType Directory | Out-Null
                    }
                }
            }
        }
                
        if ($children = $itemSpec.children) {
            foreach ($childName in $children.Keys) {
                $childPath = "{0}\{1}" -f $path, $childName

                & $buildDirectory $childPath $children[$childName] ($prefixLength + 3)
            }
        }

    }

    & $buildDirectory $ProjectPath $directoryStructure

}
# END: source\_ensureProjectDirectory.ps1


# START: source\Export-PSModuleProject.ps1
# Build.ps1 - ps-build-module - https://github.com/Adicitus/ps-build-module

<#
Build script used to compile PS Modules arranged as:
 [ProjectRoot Dir]
    |- "source" folder
    | |- 0-1 ".assets" folder.
    | |- 0-* .ps1 files.
    | |- 0-* additional nested source folders (can contain 1 .assets folder and any number of .ps1 files).
    |- "build.settings" folder
       |- modulename.ps1
       |- "manifest" folder
          |- Manifest setting file(s)
 
The script will take all of the .ps1 under the "source" folder and flatten them into a
single .psm1 file under "$OutRoot\$modulename\" directory. All assets in the .assets
folders will similarly be combined in a ".assets" folder under "$OutRoot\$modulename\".
 
The .ps1 files i a directory will be processed in lexicographical order. Subdirectories
will also be processed in this order.
#>


function Export-PSModuleProject {
    [CmdletBinding()]
    param(
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$false, Position=1)]
        [string]$ProjectRoot=".",
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$false, Position=2)]
        [string]$OutRoot = "$ProjectRoot\out"
    )

    # Build manifest
    $manifestArgs = @{}
    $buildArgs = @{}

    Get-ChildItem "$ProjectRoot\build.settings" -File | ForEach-Object {
        $name = $_.Name.split(".")[0]
        if ($_.name -like "*.ps1") {
            $buildArgs.$name = & $_.FullName
        } else {
            $buildArgs.$name = Get-Content $_.FullName
        }
    }

    Get-ChildItem "$ProjectRoot\build.settings\manifest" -File | ForEach-Object {
        $name = $_.Name.split(".")[0]
        if ($_.name -like "*.ps1") {
            $manifestArgs.$name = & $_.FullName
        } else {
            $manifestArgs.$name = (Get-Content $_.FullName) -join "`n"
        }
    }

    $moduleName = $buildArgs.modulename

    if (-not $moduleName) {
        throw "No module name set ('-not `$modulename' evaluates to `$false)!"
    }

    $SrcDir = "$ProjectRoot\source"
    $outDir = "$OutRoot\$moduleName"
    $assetsOutDir = "$outDir\.assets"

    $moduleFile     = "{0}\{1}.psm1" -f $outDir, $moduleName
    $manifestFile   = "{0}\{1}.psd1" -f $outDir, $moduleName

    if (Test-Path $outDir -PathType Container) {
        Remove-Item $outDir -Force -Recurse
    }

    $null = New-Item $outDir -ItemType Directory

    # Build Script module

    $addFolder = {
        param(
            [System.IO.DirectoryInfo]$item,
            [String]$subname
        )
        
        if ($subname) {
            "# {0}.{1}" -f $moduleName, $subname >> $moduleFile
        }

        if ($assetsDir = Get-ChildItem $item.FullName -Filter ".assets" -Directory) {
            if ( !(Test-Path $assetsOutDir) ) {
                mkdir $assetsOutDir
            }

            $assetsDir | Get-ChildItem | ForEach-Object {
                Copy-Item $_.FullName -Destination "$assetsOutDir\" -Recurse 
            }
        }

        Get-ChildItem $item.FullName -Filter *.ps1 | Sort-Object -Property Name | ForEach-Object {
            $fn = $_.FullName
            $rn = $fn.remove(0, $fn.IndexOf('source'))
            "" | Out-File  -FilePath $moduleFile -Append
            "# START: {0}" -f $rn | Out-File -FilePath $moduleFile -Append
            Get-Content $_.FullName | Out-File -FilePath $moduleFile -Append
            "# END: {0}" -f $rn | Out-File -FilePath $moduleFile -Append
            "" | Out-File  -FilePath $moduleFile -Append
        }

    }

    # Start with the root dir
    . $addFolder (Get-Item $srcDir)

    # Then include subfolders
    Get-ChildItem $srcDir -Directory -Exclude .assets | Sort-Object -Property Name | ForEach-Object {
        $item = $_

        . $addFolder $item $item.Name
    }

    $manifestArgs | Out-String | Write-Host

    # Generate the manifest
    New-ModuleManifest -Path $manifestFile @manifestArgs
}
# END: source\Export-PSModuleProject.ps1


# START: source\Initialize-PSModuleProject.ps1
function Initialize-PSModuleProject{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, Position=1)]
        [ValidateNotNullOrEmpty()]
        [string]$ProjectDirectoryPath,
        [Parameter(Mandatory=$true, Position=2)]
        [ValidateNotNullOrEmpty()]
        [string]$ModuleName,
        [Parameter(Mandatory=$true, Position=3)]
        [ValidateNotNullOrEmpty()]
        [string]$Author
    )
    
    _ensureProjectDirectory $ProjectDirectoryPath $ModuleName $Author
}
# END: source\Initialize-PSModuleProject.ps1