Skip to content

Commit

Permalink
Import all modules before processing any, to allow local links to be …
Browse files Browse the repository at this point in the history
…generated properly (issue #10)
  • Loading branch information
msorens committed Jul 23, 2017
1 parent dcbf273 commit ab9805d
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 28 deletions.
71 changes: 43 additions & 28 deletions Source/Convert-HelpToHtmlTree.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ This output is generated from the above input:
</ul>
The MSDN references are retrieved automatically from two fixed MSDN reference pages (one for cmdlets and one for "about" topics). If those fixed references ever change URLs, that will break the generator; update those URLs in the Get-CmdletDocLinks function to mend it.
Note that if you get just plain text with no hyperlink for any of the first four classes of input, chances are you have a typo, because the function or topic could not be found.
==== Output Enhancements: Formatting ====
Expand Down Expand Up @@ -302,7 +303,6 @@ function Convert-HelpToHtmlTree

Init-Variables


if ($SourceDir) {
$moduleRoot = $SourceDir
}
Expand All @@ -313,19 +313,20 @@ function Convert-HelpToHtmlTree
$Namespaces |
# Convert wildcards (if any) in Namespaces parameter to instances
% {
Get-ChildItem $moduleRoot $_ } |
Get-ChildItem -Path $moduleRoot -Filter $_ } |
% {
$namespace = $_.Name # Grab name out of DirectoryInfo object
$namespaceDir = Join-Path $moduleRoot $namespace
Write-Host "Namespace: $namespace"
$script:namespaceCount++;
$script:moduleSummary = @{}
if ($DocTitle) { $title = "{0} {1}" -f $namespace, $DocTitle }
else { $title = "$namespace Namespace"}
$namespaceDir = Join-Path $moduleRoot $namespace
$saveModuleCount = $moduleCount
Get-ChildItem $namespaceDir |
? { $_.PsIsContainer } |
% { Process-Module $namespace $_.Name $title}
# load the modules first in case there are any cross-referenced links
$modules = Import-AllModules $namespace
$modules | % { Process-Module $namespace $_ $title}
Remove-AllModules $modules
if ($saveModuleCount -eq $moduleCount) {
[void](Handle-MissingValue "No modules found");
$noModulesFlagged = $true
Expand Down Expand Up @@ -356,6 +357,25 @@ function Convert-HelpToHtmlTree

########################### Support #############################

function Import-AllModules($namespace)
{
$modules = Get-ChildItem $namespaceDir |
where { $_.PsIsContainer } |
select -ExpandProperty Name
$modules |
% {
if (! (Import-ModuleUnlessDocGeneratorItself $namespace $_))
{ [void](Handle-MissingValue "Cannot load $_ module") }
}
return $modules
}

function Remove-AllModules($modules)
{
$modules |
% { Remove-ModuleUnlessDocGeneratorItself $_ }
}

function Get-CmdletDocLinks($referenceWebPage, $topicRegex)
{
# Adapted from http://powershell.com/cs/blogs/tips/archive/2010/10/06/scraping-information-from-web-pages.aspx
Expand Down Expand Up @@ -398,29 +418,24 @@ function Process-Module($namespace, $moduleName, $parentTitle)
Write-Host " Module: $moduleName"
$script:moduleCount++;

if (! (Import-MostModules $namespace $moduleName))
{ [void](Handle-MissingValue "Cannot load $moduleName module") }
else {
if (!$parentTitle) { $parentTitle = "{0} Namespace" -f $namespace }
$moduleDocPath = Join-Path $TargetDir (Join-Path $namespace $moduleName)
if (! (Test-Path $moduleDocPath)) {
if ($PSCmdlet.ShouldProcess($moduleDocPath, "mkdir")) {
mkdir $moduleDocPath | Out-Null }
}
if (!$parentTitle) { $parentTitle = "{0} Namespace" -f $namespace }
$moduleDocPath = Join-Path $TargetDir (Join-Path $namespace $moduleName)
if (! (Test-Path $moduleDocPath)) {
if ($PSCmdlet.ShouldProcess($moduleDocPath, "mkdir")) {
mkdir $moduleDocPath | Out-Null }
}

$moduleDetails = @{}
if ($modulePropertiesInTemplate) {
$modulePropertiesInTemplate | % {
$newval = invoke-expression "(Get-Module $moduleName).$_"
$moduleDetails[$_] = $newval
}
$moduleDetails = @{}
if ($modulePropertiesInTemplate) {
$modulePropertiesInTemplate | % {
$newval = invoke-expression "(Get-Module $moduleName).$_"
$moduleDetails[$_] = $newval
}

$help = @{}
Generate-FunctionPages $moduleName $moduleDocPath $parentTitle $help
Generate-ModulePage $moduleName $moduleDocPath $parentTitle $help
Remove-MostModules $moduleName
}

$help = @{}
Generate-FunctionPages $moduleName $moduleDocPath $parentTitle $help
Generate-ModulePage $moduleName $moduleDocPath $parentTitle $help
}

function Generate-FunctionPages($moduleName, $moduleDocPath, $parentTitle, $helpHash)
Expand Down Expand Up @@ -686,7 +701,7 @@ function Handle-MissingValue($message)
}

# Convert Import-Module into a functional object
function Import-MostModules($namespace, $moduleName)
function Import-ModuleUnlessDocGeneratorItself($namespace, $moduleName)
{
# Skip reloading this module--causes all functions to be lost!
if ($moduleName -eq $thisModule) { return $true }
Expand All @@ -700,7 +715,7 @@ function Import-MostModules($namespace, $moduleName)
return ! (!$?)
}

function Remove-MostModules($moduleName)
function Remove-ModuleUnlessDocGeneratorItself($moduleName)
{
if ($moduleName -ne $thisModule) {
# Hmmm... With -WhatIf, Remove-Module complains about no modules removed
Expand Down
92 changes: 92 additions & 0 deletions Tests/DocTreeGenerator.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -920,4 +920,96 @@ $content

}

Describe 'Main' {
Mock Write-Host
Mock Write-Warning
Mock Get-CmdletDocLinks
Mock Handle-MissingValue { 'missing value' }
Mock Get-ChildItem { @{ 'name' = $Filter } }
Mock Remove-AllModules { $script:sequence += 'remove' }
Mock Process-Module { $script:sequence += 'process' }
Mock Generate-HomePage
Mock Generate-ContentsPage

It 'Imports each module in a namespace before building' {
Mock Import-AllModules { $script:sequence += 'import'; return 'm1' }
$script:sequence = @()
Convert-HelpToHtmlTree -Namespaces 'ns1'
Assert-MockCalled Import-AllModules 1 -Scope It
$sequence[0] | Should Be 'import'
$sequence[1] | Should Be 'process'
}

It 'Removes each module in a namespace after building' {
Mock Import-AllModules { $script:sequence += 'import'; return 'm1' }
$script:sequence = @()
Convert-HelpToHtmlTree -Namespaces 'ns1'
Assert-MockCalled Remove-AllModules 1 -Scope It
$sequence[1] | Should Be 'process'
$sequence[2] | Should Be 'remove'
}

It 'Processes each module in a single namespace' {
$moduleNames = 'm1','m2'
Mock Import-AllModules { return $moduleNames }
$script:sequence = @()
Convert-HelpToHtmlTree -Namespaces 'ns1'
foreach ($name in $moduleNames) {
Assert-MockCalled Process-Module 1 { $moduleName -eq $name } -Scope It
}
}

It 'Processes each module in multiple namespaces' {
$ns1Modules = @('ns1-m1', 'ns1-m2')
$ns2Modules = @('ns2-m1', 'ns2-m2', 'ns2-m3')
$namespaces = @{
'nspace1' = $ns1Modules
'nspace2' = $ns2Modules
}
# problem getting this to work!
# Mock Import-AllModules -MockWith { return $namespaces[$namespace] }
Mock Import-AllModules -MockWith { $ns1Modules } -ParameterFilter { $namespace -eq 'nspace1' }
Mock Import-AllModules -MockWith { $ns2Modules } -ParameterFilter { $namespace -eq 'nspace2' }
$script:sequence = @()
Convert-HelpToHtmlTree -Namespaces 'nspace1','nspace2'
foreach ($ns in $namespaces.keys) {
foreach ($name in $namespaces[$ns]) {
#Assert-MockCalled Process-Module 1 { $moduleName -eq $name } -Scope It
}
}
}

It 'WARNS about no namespaces when supplied argument does not resolve to path' {
Mock Import-AllModules
Mock Get-ChildItem { @() }
Convert-HelpToHtmlTree -Namespaces 'unknownNamespace'
Assert-MockCalled Handle-MissingValue 1 { $message -eq 'No namespaces found' } -scope It
}

It 'Does NOT warn about no namespaces when supplied argument resolves to path' {
Mock Import-AllModules { return 'm1' }
Mock Get-ChildItem { @{ 'name' = $Filter } }
# emulate real Process-Module with respect to generating warning
Mock Process-Module { $script:moduleCount++ }
Convert-HelpToHtmlTree -Namespaces 'ns1'
Assert-MockCalled Handle-MissingValue 0 -Scope It
}

It 'WARNS about no modules when namespace dir has none' {
Mock Import-AllModules { @() }
Mock Get-ChildItem { @{ 'name' = $Filter } }
Mock Process-Module { $script:moduleCount++ }
Convert-HelpToHtmlTree -Namespaces 'ns1'
Assert-MockCalled Handle-MissingValue 1 { $message -eq 'No modules found' } -scope It
}
It 'Does NOT warn about no modules when modules present' {
Mock Import-AllModules { 'm1' }
Mock Get-ChildItem { @{ 'name' = $Filter } }
Mock Process-Module { $script:moduleCount++ }
Convert-HelpToHtmlTree -Namespaces 'ns1'
Assert-MockCalled Handle-MissingValue 0 -scope It
}
}


}

0 comments on commit ab9805d

Please sign in to comment.