контекст / настройка
Я работаю над довольно большим инструментом автоматизации сборки, который на 90% состоит из кода PowerShell.
Многие функции сгруппированы в файлах .psm1, которые загружают друг друга с помощью
Import-Module "$PSScriptRoot/AnotherModule.psm1" -Force
это казалось хорошей идеей для разработки / тестирования кода и т. д., но недавно я наткнулся на проблему с этим подходом.
поиск / проблема
всякий раз, когда загруженный модуль принудительно импортирует другой модуль, который ранее был загружен в родительской / внешней области, он больше не доступен в этой родительской / внешней области
теперь я столкнулся с проблемой, когда импорт необходимых модулей в начале скрипта не гарантирует, что импортированные модули действительно доступны во время выполнения скрипта, поскольку один из импортированных модулей может «скрыть» другой, ранее загруженный модуль: - /
пример
допустим, у нас есть три модуля: ModA, ModB, ModC:
ModA:
$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot\ModB.psm1" -Force
// module A entrails
ModB:
$ErrorActionPreference = "Stop"
// module B entrails
ModC:
$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot\ModA.psm1" -Force
// module C entrails
Следующие тесты pester демонстрируют это «скрытие модуля»:
Describe 'powershell module system tests' {
# ModA -> Import ModB -Force
# ModC -> Import ModA -Force
$mod_path = Join-Path $PSScriptRoot "testmod"
$mods = @("ModA", "ModB", "ModC")
It "cleanup leftovers from previous tests" {
Remove-Module $mods -ErrorAction SilentlyContinue
}
It 'is able to import ModA, which internally loads module B' {
Import-Module "$mod_path\ModA.psm1" -Force
Get-Module ModA | Should -Not -BeNullOrEmpty
Get-Module ModB | Should -BeNullOrEmpty
}
It 'is able to import a second module already imported by the first one' {
Get-Module ModA | Should -Not -BeNullOrEmpty
Import-Module "$mod_path\ModB.psm1" -Force
Get-Module ModB | Should -Not -BeNullOrEmpty
}
It 'still knows the first module' {
Get-Module ModA | Should -Not -BeNullOrEmpty
}
It 'is able to import a thid module that also imports the first one' {
Get-Module ModC | Should -BeNullOrEmpty
Import-Module "$mod_path\ModC.psm1" -Force
Get-Module ModC | Should -Not -BeNullOrEmpty
}
It 'does not know A or B any longer, as it has been hidden by C' {
Get-Module ModA | Should -BeNullOrEmpty
Get-Module ModB | Should -BeNullOrEmpty
}
It 'still knows C' {
Get-Module ModC | Should -Not -BeNullOrEmpty
}
It 'cleanup leftovers from this test' {
Remove-Module $mods
}
}
отслеживание ошибок
чтобы точно определить проблему (ы), я попытался придумать еще один тест на приставку, который анализирует кодовую базу и проверяет, что ни один из «уже загруженных» модулей не удален из глобальной таблицы модулей при импорте другого:
Describe 'verify tool module system hierachy' {
$tool_modules = Get-ChildItem $script:engine_path -Filter "*.psm1"
function UNLoadAllToolModules {
Remove-Module 'Tool-*'
}
function LoadAllToolModules {
$tool_modules | Foreach-Object { Import-Module $_.FullName }
}
It "cleanup leftovers from previous tests" {
UNLoadAllToolModules
}
It "loading of a module does not hide an already loaded module" {
$errMods = $()
$tool_modules | ForEach-Object {
LoadAllToolModules
$pre = Get-Module
$mod = $_
Import-Module $mod.FullName -Force
$post = Get-Module
$mods = Compare-Object $post $pre | Select-Object -Expand InputObject | Select-Object -Expand Name
$mods | Foreach-Object {
"import of '$mod' hides '$_'" | Write-Host
}
if ($mods) {
$errMods += $mod.Name
}
}
$errMods | Should -BeNullOrEmpty
}
}
вопрос
есть ли способ распечатать / отладить глобальную таблицу модулей, как показано здесь, чтобы я мог выяснить, какой модуль загружается несколько раз / как изменяется дерево модулей после импорта?
решение?
в настоящее время единственный способ обойти эту «проблему» (впрочем, это, вероятно, плохой выбор дизайна для принудительного импорта модулей в другие модули) - либо отказаться от -force
, либо использовать -global
каждый раз при вызове Import-Module -Force
модуля, содержащегося в этом пакете автоматизации сборки /орудие труда.