From 82cd049fd56097fb4768c09bd3630e3d2ae8b6e7 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sat, 7 Jan 2017 17:37:58 -0700 Subject: [PATCH 1/9] WIP check user profile during interactive import. Offer to update their current/all host profile if posh-git not detected in their profile scripts. Note: we do not offer to update the "all users" profile scripts because that requires elevation and probably not worth it. Add Pester tests for the new Utils.ps1 functions. --- Utils.ps1 | 130 +++++++++++++++++++++++++++++++++++++- install.ps1 | 19 +----- posh-git.psm1 | 55 +++++++++++++++- test/Utils.Tests.ps1 | 122 +++++++++++++++++++++++++++++++++++ test/testDebugHarness.ps1 | 2 + 5 files changed, 307 insertions(+), 21 deletions(-) create mode 100644 test/Utils.Tests.ps1 create mode 100644 test/testDebugHarness.ps1 diff --git a/Utils.ps1 b/Utils.ps1 index 543033208..73132eb60 100644 --- a/Utils.ps1 +++ b/Utils.ps1 @@ -5,7 +5,8 @@ function Invoke-NullCoalescing { foreach($arg in $args) { if ($arg -is [ScriptBlock]) { $result = & $arg - } else { + } + else { $result = $arg } if ($result) { break } @@ -26,6 +27,98 @@ function Invoke-Utf8ConsoleCommand ([ScriptBlock]$cmd) { } } +function Add-ImportModuleToProfile { + param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $ProfilePath, + + # This is only required to support PS v2 there $PSScriptRoot only works in a .psm1 file + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $ScriptRoot + ) + + # Check if profile script exists + if (Test-Path -LiteralPath $profilePath) { + $profileContent = @(Get-Content -LiteralPath $profilePath) + $profileContent += [string]::Empty # Empty line between previous profile script and import statement + $encoding = Get-FileEncoding $profilePath + } + else { + # Doesn't exist, so create it + New-Item -Path $profilePath -ItemType File + $profileContent = @() + $encoding = 'ascii' + } + + # Check if the location of this module file is in the PSModulePath + if (Test-InModulePath $ScriptRoot) { + $profileContent += "Import-Module posh-git" + } + else { + $profileContent += "Import-Module '$ScriptRoot\posh-git.psd1'" + } + + Set-Content -LiteralPath $profilePath -Value $profileContent -Encoding $encoding +} + +<# +.SYNOPSIS + Gets the file encoding of the specified file. +.DESCRIPTION + Gets the file encoding of the specified file. +.PARAMETER Path + Path to the file to check. The file must exist. +.EXAMPLE + PS C:\> Get-FileEncoding $profile + Get's the file encoding of the profile file. +.INPUTS + None. +.OUTPUTS + [System.String] +.NOTES + Adapted from http://www.west-wind.com/Weblog/posts/197245.aspx +#> +function Get-FileEncoding($Path) { + $bytes = [byte[]](Get-Content $Path -Encoding byte -ReadCount 4 -TotalCount 4) + + if (!$bytes) { return 'utf8' } + + switch -regex ('{0:x2}{1:x2}{2:x2}{3:x2}' -f $bytes[0],$bytes[1],$bytes[2],$bytes[3]) { + '^efbbbf' { return 'utf8' } + '^2b2f76' { return 'utf7' } + '^fffe' { return 'unicode' } + '^feff' { return 'bigendianunicode' } + '^0000feff' { return 'utf32' } + default { return 'ascii' } + } +} + +<# +.SYNOPSIS + Gets a StringComparison enum value appropriate for comparing paths on the OS platform. +.DESCRIPTION + Gets a StringComparison enum value appropriate for comparing paths on the OS platform. +.EXAMPLE + PS C:\> $pathStringComparison = Get-PathStringComparison +.INPUTS + None +.OUTPUTS + [System.StringComparison] +#> +function Get-PathStringComparison { + # File system paths are case-sensitive on Linux and case-insensitive on Windows and macOS + if (($PSVersionTable.PSVersion.Major -ge 6) -and $IsLinux) { + [System.StringComparison]::Ordinal + } + else { + [System.StringComparison]::OrdinalIgnoreCase + } +} + function Get-LocalOrParentPath($path) { $checkIn = Get-Item -Force . if ($checkIn.PSProvider.Name -ne 'FileSystem') { @@ -35,15 +128,46 @@ function Get-LocalOrParentPath($path) { $pathToTest = [System.IO.Path]::Combine($checkIn.fullname, $path) if (Test-Path -LiteralPath $pathToTest) { return $pathToTest - } else { + } + else { $checkIn = $checkIn.parent } } return $null } +function Test-InModulePath { + param ( + [Parameter(Position=0, Mandatory=$true)] + [ValidateNotNull()] + [string] + $Path + ) + + $modulePaths = $env:PSModulePath -split ';' + if (!$modulePaths) { return $false } + + $pathStringComparison = Get-PathStringComparison + $inModulePath = @($modulePaths | Where-Object { $Path.StartsWith($_, $pathStringComparison) }).Count -gt 0 + $inModulePath +} + +function Test-PoshGitImportedInScript { + param ( + [Parameter(Position=0, Mandatory=$true)] + [string] + $Path + ) + + if (!$Path -or !(Test-Path -LiteralPath $Path)) { + return $false + } + + @((Get-Content $Path -ErrorAction SilentlyContinue) -match 'posh-git').Count -gt 0 +} + function dbg ($Message, [Diagnostics.Stopwatch]$Stopwatch) { - if($Stopwatch) { + if ($Stopwatch) { Write-Verbose ('{0:00000}:{1}' -f $Stopwatch.ElapsedMilliseconds,$Message) -Verbose # -ForegroundColor Yellow } } diff --git a/install.ps1 b/install.ps1 index 22fa88552..9d0b8efed 100644 --- a/install.ps1 +++ b/install.ps1 @@ -1,5 +1,8 @@ param([switch]$WhatIf = $false) +# Dot source for Get-FileEncoding +. $PSScriptRoot\Utils.ps1 + if($PSVersionTable.PSVersion.Major -lt 2) { Write-Warning "posh-git requires PowerShell 2.0 or better; you have version $($Host.Version)." return @@ -20,22 +23,6 @@ if(!(. (Join-Path $installDir "CheckVersion.ps1"))) { return } -# Adapted from http://www.west-wind.com/Weblog/posts/197245.aspx -function Get-FileEncoding($Path) { - $bytes = [byte[]](Get-Content $Path -Encoding byte -ReadCount 4 -TotalCount 4) - - if(!$bytes) { return 'utf8' } - - switch -regex ('{0:x2}{1:x2}{2:x2}{3:x2}' -f $bytes[0],$bytes[1],$bytes[2],$bytes[3]) { - '^efbbbf' { return 'utf8' } - '^2b2f76' { return 'utf7' } - '^fffe' { return 'unicode' } - '^feff' { return 'bigendianunicode' } - '^0000feff' { return 'utf32' } - default { return 'ascii' } - } -} - $profileLine = ". '$installDir\profile.example.ps1'" if(Select-String -Path $PROFILE -Pattern $profileLine -Quiet -SimpleMatch) { Write-Host "It seems posh-git is already installed..." diff --git a/posh-git.psm1 b/posh-git.psm1 index b4120c73a..ffde35ec5 100644 --- a/posh-git.psm1 +++ b/posh-git.psm1 @@ -1,4 +1,4 @@ -param([switch]$NoVersionWarn) +param([switch]$NoVersionWarn, [switch]$NoProfileCheck) if (Get-Module posh-git) { return } @@ -38,7 +38,7 @@ $poshGitPromptScriptBlock = $null $currentPromptDef = if ($funcInfo = Get-Command prompt -ErrorAction SilentlyContinue) { $funcInfo.Definition } -# HACK: If prompt is missing, create a global one we can overwrite with Set-Item +# HACK: If prompt is missing, create a global one we can overwrite with Set-Item if (!$currentPromptDef) { function global:prompt { ' ' } } @@ -92,6 +92,57 @@ if (!$currentPromptDef -or ($currentPromptDef -eq $defaultPromptDef)) { Set-Item Function:\prompt -Value $poshGitPromptScriptBlock } +# If running interactive, check if user want's `import-module posh-git` added to their profile +if (!$NoProfileCheck -and ($MyInvocation.ScriptName.Length -eq 0)) { + # Search the current user profiles for current host & all host for the string "posh-git" which covers the + # way Chocolatey installs modify the profile e.g. . C:\tools\posh-git\... Also handle the case where there are no + # profile scripts created yet. + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserCurrentHost + if (!$importedInProfile) { + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserAllHosts + } + if (!$importedInProfile) { + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.AllUsersCurrentHost + } + if (!$importedInProfile) { + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.AllUsersAllHosts + } + + # If we have not detected "posh-git" in the user's profile scripts, ask if they want their profile to import posh-git + if (!$importedInProfile) { + $title = "Modify Profile" + $message = "Do you want posh-git to modify your profile to automatically import this module whenever your start PowerShell?" + + $argList = @( + "&Yes, for the current PowerShell host", + "Modify the profile for $($Host.Name) to automatically import posh-git." + ) + $yesCurrent = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList $argList + + $argList = @( + "Yes, for &all PowerShell hosts", + "Modify the profile for all hosts to automatically import posh-git." + ) + $yesAll = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList $argList + + $argList = @( + "&No", + "Do not modify my profile. To suppress this prompt in the future, execute: Import-Module posh-git -Arg `$false, `$true" + ) + $no = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList $argList + + $options = [System.Management.Automation.Host.ChoiceDescription[]]($yesCurrent, $yesAll, $no) + + $result = $host.UI.PromptForChoice($title, $message, $options, 0) + switch ($result) { + 0 { Add-ImportModuleToProfile $PROFILE.CurrentUserCurrentHost $PSScriptRoot } + 1 { Add-ImportModuleToProfile $PROFILE.CurrentUserAllHosts $PSScriptRoot } + 2 { } # Nothing to do if user picks 'No' + default { throw "Unexpected choice result: $result" } + } + } +} + # Install handler for removal/unload of the module $ExecutionContext.SessionState.Module.OnRemove = { $global:VcsPromptStatuses = $global:VcsPromptStatuses | Where-Object { $_ -ne $PoshGitVcsPrompt } diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 new file mode 100644 index 000000000..8c1c045b9 --- /dev/null +++ b/test/Utils.Tests.ps1 @@ -0,0 +1,122 @@ +. $PSScriptRoot\..\Utils.ps1 + +Describe 'Utils Function Tests' { + Context 'Add-ImportModuleToProfile Tests' { + BeforeAll { + $newLine = [System.Environment]::NewLine + } + It 'Creates profile file if it does not exist' { + $profilePath = [System.IO.Path]::GetTempFileName() + Remove-Item -LiteralPath $profilePath + Test-Path -LiteralPath $profilePath | Should Be $false + try { + $scriptRoot = Split-Path $profilePath -Parent + Add-ImportModuleToProfile $profilePath $scriptRoot + Test-Path -LiteralPath $profilePath | Should Be $true + Get-FileEncoding $profilePath | Should Be 'ascii' + $content = Get-Content $profilePath + $content.Count | Should Be 1 + @($content)[0] | Should BeExactly "Import-Module '$scriptRoot\posh-git.psd1'" + } + finally { + Remove-Item $profilePath -ErrorAction SilentlyContinue + } + } + It 'Modifies existing (Unicode) profile file correctly' { + $profilePath = [System.IO.Path]::GetTempFileName() + $profileContent = @' +Import-Module PSCX + +New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win-core\bin\Debug\netcoreapp1.1\win10-x64\powershell.exe +'@ + Set-Content $profilePath -Value $profileContent -Encoding Unicode + try { + $scriptRoot = Split-Path $profilePath -Parent + Add-ImportModuleToProfile $profilePath $scriptRoot + Test-Path -LiteralPath $profilePath | Should Be $true + Get-FileEncoding $profilePath | Should Be 'unicode' + $content = Get-Content $profilePath + $content.Count | Should Be 5 + $profileContent += "${newLine}${newLine}Import-Module '$scriptRoot\posh-git.psd1'" + $content -join $newLine | Should BeExactly $profileContent + } + finally { + Remove-Item $profilePath -ErrorAction SilentlyContinue + } + } + } + + Context 'Test-PoshGitImportedInScript Tests' { + It 'Detects Import-Module posh-git in profile script' { + $profilePath = [System.IO.Path]::GetTempFileName() + $profileContent = "Import-Module posh-git" + Set-Content $profilePath -Value $profileContent -Encoding Unicode + try { + Test-PoshGitImportedInScript $profilePath | Should Be $true + } + finally { + Remove-Item $profilePath -ErrorAction SilentlyContinue + } + } + It 'Detects chocolatey installed line in profile script' { + $profilePath = [System.IO.Path]::GetTempFileName() + $profileContent = ". 'C:\tools\poshgit\dahlbyk-posh-git-18d600a\profile.example.ps1" + Set-Content $profilePath -Value $profileContent -Encoding Unicode + try { + Test-PoshGitImportedInScript $profilePath | Should Be $true + } + finally { + Remove-Item $profilePath -ErrorAction SilentlyContinue + } + } + It 'Returns false when profile script does not import posh-git' { + $profilePath = [System.IO.Path]::GetTempFileName() + $profileContent = "Import-Module Pscx`nImport-Module platyPS`nImport-Module Plaster" + Set-Content $profilePath -Value $profileContent -Encoding Unicode + try { + Test-PoshGitImportedInScript $profilePath | Should Be $false + } + finally { + Remove-Item $profilePath -ErrorAction SilentlyContinue + } + } + } + + Context 'Test-InModulePath Tests' { + BeforeAll { + $standardPSModulePath = "C:\Users\Keith\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\" + } + BeforeEach { + $origPSModulePath = $env:PSModulePath + } + AfterEach { + $env:PSModulePath = $origPSModulePath + } + It 'Works for install from PSGallery to current user modules location' { + $env:PSModulePath = $standardPSModulePath + $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" + Test-InModulePath $path | Should Be $true + } + It 'Works for install from Chocolatey not in any modules path' { + $env:PSModulePath = $standardPSModulePath + $path = "C:\tools\posh-git\dahlbyk-posh-git-18d600a" + Test-InModulePath $path | Should Be $false + } + It 'Works for running from posh-git Git repo and location not in modules path' { + $env:PSModulePath = $standardPSModulePath + $path = "C:\Users\Keith\GitHub\posh-git" + Test-InModulePath $path | Should Be $false + } + It 'Returns false when PSModulePath is empty' { + $env:PSModulePath = '' + $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" + Test-InModulePath $path | Should Be $false + } + It 'Returns false when PSModulePath is missing' { + Remove-Item Env:\PSModulePath + Test-Path Env:\PSModulePath | Should Be $false + $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" + Test-InModulePath $path | Should Be $false + } + } +} diff --git a/test/testDebugHarness.ps1 b/test/testDebugHarness.ps1 new file mode 100644 index 000000000..346fb6b0e --- /dev/null +++ b/test/testDebugHarness.ps1 @@ -0,0 +1,2 @@ + +Invoke-Pester $PSScriptRoot\Utils.Tests.ps1 From f3d49730644fa768623438a2f913985d11a8ec88 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sat, 7 Jan 2017 23:01:40 -0700 Subject: [PATCH 2/9] Clean up comments and import choice script. --- posh-git.psm1 | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/posh-git.psm1 b/posh-git.psm1 index ffde35ec5..dc9af64e8 100644 --- a/posh-git.psm1 +++ b/posh-git.psm1 @@ -92,11 +92,9 @@ if (!$currentPromptDef -or ($currentPromptDef -eq $defaultPromptDef)) { Set-Item Function:\prompt -Value $poshGitPromptScriptBlock } -# If running interactive, check if user want's `import-module posh-git` added to their profile +# IFF running interactive, check if user wants their profile script to be modified to import the module if (!$NoProfileCheck -and ($MyInvocation.ScriptName.Length -eq 0)) { - # Search the current user profiles for current host & all host for the string "posh-git" which covers the - # way Chocolatey installs modify the profile e.g. . C:\tools\posh-git\... Also handle the case where there are no - # profile scripts created yet. + # Search the user's profiles to see if any are using posh-git already $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserCurrentHost if (!$importedInProfile) { $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserAllHosts @@ -108,31 +106,27 @@ if (!$NoProfileCheck -and ($MyInvocation.ScriptName.Length -eq 0)) { $importedInProfile = Test-PoshGitImportedInScript $PROFILE.AllUsersAllHosts } - # If we have not detected "posh-git" in the user's profile scripts, ask if they want their profile to import posh-git + # If we haven't detected that a profile script is using posh-git, ask if they want their profile modified to import posh-git if (!$importedInProfile) { - $title = "Modify Profile" - $message = "Do you want posh-git to modify your profile to automatically import this module whenever your start PowerShell?" - - $argList = @( + $yesCurrent = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList @( "&Yes, for the current PowerShell host", "Modify the profile for $($Host.Name) to automatically import posh-git." ) - $yesCurrent = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList $argList - $argList = @( + $yesAll = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList @( "Yes, for &all PowerShell hosts", "Modify the profile for all hosts to automatically import posh-git." ) - $yesAll = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList $argList - $argList = @( + $no = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList @( "&No", "Do not modify my profile. To suppress this prompt in the future, execute: Import-Module posh-git -Arg `$false, `$true" ) - $no = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList $argList $options = [System.Management.Automation.Host.ChoiceDescription[]]($yesCurrent, $yesAll, $no) + $title = "Modify Profile" + $message = "Do you want posh-git to modify your profile to automatically import this module whenever your start PowerShell?" $result = $host.UI.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 { Add-ImportModuleToProfile $PROFILE.CurrentUserCurrentHost $PSScriptRoot } From 2ac0b187fb88ac562f3e1a17fbb1528205ce35f8 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 8 Jan 2017 00:48:12 -0700 Subject: [PATCH 3/9] Change to utf8 and use Before/AfterEach. Remove $PSScriptRoot from install.ps1. --- Utils.ps1 | 2 +- install.ps1 | 3 +- test/Utils.Tests.ps1 | 78 +++++++++++++++++--------------------------- 3 files changed, 33 insertions(+), 50 deletions(-) diff --git a/Utils.ps1 b/Utils.ps1 index 73132eb60..9281bb82b 100644 --- a/Utils.ps1 +++ b/Utils.ps1 @@ -51,7 +51,7 @@ function Add-ImportModuleToProfile { # Doesn't exist, so create it New-Item -Path $profilePath -ItemType File $profileContent = @() - $encoding = 'ascii' + $encoding = 'utf8' } # Check if the location of this module file is in the PSModulePath diff --git a/install.ps1 b/install.ps1 index 9d0b8efed..b2a5cc4cc 100644 --- a/install.ps1 +++ b/install.ps1 @@ -1,7 +1,8 @@ param([switch]$WhatIf = $false) # Dot source for Get-FileEncoding -. $PSScriptRoot\Utils.ps1 +$scriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +. $scriptRoot\Utils.ps1 if($PSVersionTable.PSVersion.Major -lt 2) { Write-Warning "posh-git requires PowerShell 2.0 or better; you have version $($Host.Version)." diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index 8c1c045b9..59966bd09 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -5,80 +5,62 @@ Describe 'Utils Function Tests' { BeforeAll { $newLine = [System.Environment]::NewLine } - It 'Creates profile file if it does not exist' { + BeforeEach { $profilePath = [System.IO.Path]::GetTempFileName() + } + AfterEach { + Remove-Item $profilePath -ErrorAction SilentlyContinue + } + It 'Creates profile file if it does not exist' { Remove-Item -LiteralPath $profilePath Test-Path -LiteralPath $profilePath | Should Be $false - try { - $scriptRoot = Split-Path $profilePath -Parent - Add-ImportModuleToProfile $profilePath $scriptRoot - Test-Path -LiteralPath $profilePath | Should Be $true - Get-FileEncoding $profilePath | Should Be 'ascii' - $content = Get-Content $profilePath - $content.Count | Should Be 1 - @($content)[0] | Should BeExactly "Import-Module '$scriptRoot\posh-git.psd1'" - } - finally { - Remove-Item $profilePath -ErrorAction SilentlyContinue - } + $scriptRoot = Split-Path $profilePath -Parent + Add-ImportModuleToProfile $profilePath $scriptRoot + Test-Path -LiteralPath $profilePath | Should Be $true + Get-FileEncoding $profilePath | Should Be 'utf8' + $content = Get-Content $profilePath + $content.Count | Should Be 1 + @($content)[0] | Should BeExactly "Import-Module '$scriptRoot\posh-git.psd1'" } It 'Modifies existing (Unicode) profile file correctly' { - $profilePath = [System.IO.Path]::GetTempFileName() $profileContent = @' Import-Module PSCX New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win-core\bin\Debug\netcoreapp1.1\win10-x64\powershell.exe '@ Set-Content $profilePath -Value $profileContent -Encoding Unicode - try { - $scriptRoot = Split-Path $profilePath -Parent - Add-ImportModuleToProfile $profilePath $scriptRoot - Test-Path -LiteralPath $profilePath | Should Be $true - Get-FileEncoding $profilePath | Should Be 'unicode' - $content = Get-Content $profilePath - $content.Count | Should Be 5 - $profileContent += "${newLine}${newLine}Import-Module '$scriptRoot\posh-git.psd1'" - $content -join $newLine | Should BeExactly $profileContent - } - finally { - Remove-Item $profilePath -ErrorAction SilentlyContinue - } + $scriptRoot = Split-Path $profilePath -Parent + Add-ImportModuleToProfile $profilePath $scriptRoot + Test-Path -LiteralPath $profilePath | Should Be $true + Get-FileEncoding $profilePath | Should Be 'unicode' + $content = Get-Content $profilePath + $content.Count | Should Be 5 + $profileContent += "${newLine}${newLine}Import-Module '$scriptRoot\posh-git.psd1'" + $content -join $newLine | Should BeExactly $profileContent } } Context 'Test-PoshGitImportedInScript Tests' { - It 'Detects Import-Module posh-git in profile script' { + BeforeEach { $profilePath = [System.IO.Path]::GetTempFileName() + } + AfterEach { + Remove-Item $profilePath -ErrorAction SilentlyContinue + } + It 'Detects Import-Module posh-git in profile script' { $profileContent = "Import-Module posh-git" Set-Content $profilePath -Value $profileContent -Encoding Unicode - try { - Test-PoshGitImportedInScript $profilePath | Should Be $true - } - finally { - Remove-Item $profilePath -ErrorAction SilentlyContinue - } + Test-PoshGitImportedInScript $profilePath | Should Be $true } It 'Detects chocolatey installed line in profile script' { - $profilePath = [System.IO.Path]::GetTempFileName() $profileContent = ". 'C:\tools\poshgit\dahlbyk-posh-git-18d600a\profile.example.ps1" Set-Content $profilePath -Value $profileContent -Encoding Unicode - try { - Test-PoshGitImportedInScript $profilePath | Should Be $true - } - finally { - Remove-Item $profilePath -ErrorAction SilentlyContinue - } + Test-PoshGitImportedInScript $profilePath | Should Be $true } It 'Returns false when profile script does not import posh-git' { - $profilePath = [System.IO.Path]::GetTempFileName() $profileContent = "Import-Module Pscx`nImport-Module platyPS`nImport-Module Plaster" Set-Content $profilePath -Value $profileContent -Encoding Unicode - try { - Test-PoshGitImportedInScript $profilePath | Should Be $false - } - finally { - Remove-Item $profilePath -ErrorAction SilentlyContinue - } + Test-PoshGitImportedInScript $profilePath | Should Be $false } } From bbabf703c52a9be6be6e4af8f9965295b2487149 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 8 Jan 2017 12:45:50 -0700 Subject: [PATCH 4/9] Simplfy check of $MyInvocation.ScriptName. --- posh-git.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posh-git.psm1 b/posh-git.psm1 index dc9af64e8..914c36429 100644 --- a/posh-git.psm1 +++ b/posh-git.psm1 @@ -93,7 +93,7 @@ if (!$currentPromptDef -or ($currentPromptDef -eq $defaultPromptDef)) { } # IFF running interactive, check if user wants their profile script to be modified to import the module -if (!$NoProfileCheck -and ($MyInvocation.ScriptName.Length -eq 0)) { +if (!$NoProfileCheck -and !$MyInvocation.ScriptName) { # Search the user's profiles to see if any are using posh-git already $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserCurrentHost if (!$importedInProfile) { From 8eac20049bd5fa1de6acfaa764092c4bb52e8719 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 8 Jan 2017 13:22:14 -0700 Subject: [PATCH 5/9] Remove extra call to Split-Path $MyInvocation ... --- install.ps1 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/install.ps1 b/install.ps1 index b2a5cc4cc..e75b1e34b 100644 --- a/install.ps1 +++ b/install.ps1 @@ -1,8 +1,8 @@ param([switch]$WhatIf = $false) # Dot source for Get-FileEncoding -$scriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent -. $scriptRoot\Utils.ps1 +$installDir = Split-Path $MyInvocation.MyCommand.Path -Parent +. $installDir\Utils.ps1 if($PSVersionTable.PSVersion.Major -lt 2) { Write-Warning "posh-git requires PowerShell 2.0 or better; you have version $($Host.Version)." @@ -19,7 +19,6 @@ if(!(Get-Command git -ErrorAction SilentlyContinue)) { return } -$installDir = Split-Path $MyInvocation.MyCommand.Path -Parent if(!(. (Join-Path $installDir "CheckVersion.ps1"))) { return } From ff4646a640910f32d3efa562cfd64d9b37305726 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 8 Jan 2017 14:33:44 -0700 Subject: [PATCH 6/9] Use Get-Module -List instead of PSModulePath. However to get the Pester tests to work I had to put the Get-Module -List command in its own function and I mock that function. Mocking Get-Module was resulting in some really weird bug about a write error trying to set PSEdition. --- Utils.ps1 | 18 ++++++++------ test/Utils.Tests.ps1 | 59 +++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/Utils.ps1 b/Utils.ps1 index 9281bb82b..9a29a7f08 100644 --- a/Utils.ps1 +++ b/Utils.ps1 @@ -16,7 +16,7 @@ function Invoke-NullCoalescing { Set-Alias ?? Invoke-NullCoalescing -Force -function Invoke-Utf8ConsoleCommand ([ScriptBlock]$cmd) { +function Invoke-Utf8ConsoleCommand([ScriptBlock]$cmd) { $currentEncoding = [Console]::OutputEncoding try { [Console]::OutputEncoding = [Text.Encoding]::UTF8 @@ -38,7 +38,7 @@ function Add-ImportModuleToProfile { [Parameter(Position = 1, Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] - $ScriptRoot + $ModuleBasePath ) # Check if profile script exists @@ -55,11 +55,11 @@ function Add-ImportModuleToProfile { } # Check if the location of this module file is in the PSModulePath - if (Test-InModulePath $ScriptRoot) { + if (Test-InPSModulePath $ModuleBasePath) { $profileContent += "Import-Module posh-git" } else { - $profileContent += "Import-Module '$ScriptRoot\posh-git.psd1'" + $profileContent += "Import-Module '$ModuleBasePath\posh-git.psd1'" } Set-Content -LiteralPath $profilePath -Value $profileContent -Encoding $encoding @@ -136,7 +136,11 @@ function Get-LocalOrParentPath($path) { return $null } -function Test-InModulePath { +function Get-PoshGitModulePath { + Get-Module posh-git -ListAvailable | ForEach-Object { $_.ModuleBase } +} + +function Test-InPSModulePath { param ( [Parameter(Position=0, Mandatory=$true)] [ValidateNotNull()] @@ -144,7 +148,7 @@ function Test-InModulePath { $Path ) - $modulePaths = $env:PSModulePath -split ';' + $modulePaths = Get-PoshGitModulePath if (!$modulePaths) { return $false } $pathStringComparison = Get-PathStringComparison @@ -166,7 +170,7 @@ function Test-PoshGitImportedInScript { @((Get-Content $Path -ErrorAction SilentlyContinue) -match 'posh-git').Count -gt 0 } -function dbg ($Message, [Diagnostics.Stopwatch]$Stopwatch) { +function dbg($Message, [Diagnostics.Stopwatch]$Stopwatch) { if ($Stopwatch) { Write-Verbose ('{0:00000}:{1}' -f $Stopwatch.ElapsedMilliseconds,$Message) -Verbose # -ForegroundColor Yellow } diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index 59966bd09..c827e6c88 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -64,41 +64,38 @@ New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win- } } - Context 'Test-InModulePath Tests' { - BeforeAll { - $standardPSModulePath = "C:\Users\Keith\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\" - } - BeforeEach { - $origPSModulePath = $env:PSModulePath - } - AfterEach { - $env:PSModulePath = $origPSModulePath - } - It 'Works for install from PSGallery to current user modules location' { - $env:PSModulePath = $standardPSModulePath + Context 'Test-InPSModulePath Tests' { + It 'Returns false for install not under any PSModulePaths' { + Mock Get-PoshGitModulePath { } $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" - Test-InModulePath $path | Should Be $true + Test-InPSModulePath $path | Should Be $false + Assert-MockCalled Get-PoshGitModulePath } - It 'Works for install from Chocolatey not in any modules path' { - $env:PSModulePath = $standardPSModulePath - $path = "C:\tools\posh-git\dahlbyk-posh-git-18d600a" - Test-InModulePath $path | Should Be $false - } - It 'Works for running from posh-git Git repo and location not in modules path' { - $env:PSModulePath = $standardPSModulePath - $path = "C:\Users\Keith\GitHub\posh-git" - Test-InModulePath $path | Should Be $false - } - It 'Returns false when PSModulePath is empty' { - $env:PSModulePath = '' + It 'Returns true for install under single PSModulePath' { + Mock Get-PoshGitModulePath { + return 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0' + } $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" - Test-InModulePath $path | Should Be $false - } - It 'Returns false when PSModulePath is missing' { - Remove-Item Env:\PSModulePath - Test-Path Env:\PSModulePath | Should Be $false + Test-InPSModulePath $path | Should Be $true + Assert-MockCalled Get-PoshGitModulePath + } + It 'Returns true for install under multiple PSModulePaths' { + Mock Get-PoshGitModulePath { + return 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0', + 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.6.1.20160330' + } $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" - Test-InModulePath $path | Should Be $false + Test-InPSModulePath $path | Should Be $true + Assert-MockCalled Get-PoshGitModulePath + } + It 'Returns false when current posh-git module location is not under PSModulePaths' { + Mock Get-PoshGitModulePath { + return 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0', + 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.6.1.20160330' + } + $path = "C:\tools\posh-git\dahlbyk-posh-git-18d600a" + Test-InPSModulePath $path | Should Be $false + Assert-MockCalled Get-PoshGitModulePath } } } From 972d53908b2708b4415c26cf0b4e5713f4c3413d Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Mon, 9 Jan 2017 09:35:04 -0700 Subject: [PATCH 7/9] See if callstack check works better. Committing this so I can test it on some other systems - via remoting. --- posh-git.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posh-git.psm1 b/posh-git.psm1 index 914c36429..fc1840582 100644 --- a/posh-git.psm1 +++ b/posh-git.psm1 @@ -93,7 +93,7 @@ if (!$currentPromptDef -or ($currentPromptDef -eq $defaultPromptDef)) { } # IFF running interactive, check if user wants their profile script to be modified to import the module -if (!$NoProfileCheck -and !$MyInvocation.ScriptName) { +if (!$NoProfileCheck -and ($stack = Get-PSCallStack) -and ($stack.Count -eq 2)) { # Search the user's profiles to see if any are using posh-git already $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserCurrentHost if (!$importedInProfile) { From f51b3db06a9472daee7d745aff3dd712306beac1 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Tue, 10 Jan 2017 23:44:10 -0700 Subject: [PATCH 8/9] Remove modify profile from module import. Now there is an Add-PoshGitToProfile command. I have a couple of Pester tests but I need to add a few more. --- Utils.ps1 | 91 +++++++++++++++++++++++++++++++------------- posh-git.psd1 | 1 + posh-git.psm1 | 51 ++----------------------- test/Shared.ps1 | 2 +- test/Utils.Tests.ps1 | 16 ++++---- 5 files changed, 78 insertions(+), 83 deletions(-) diff --git a/Utils.ps1 b/Utils.ps1 index 9a29a7f08..5589c44e7 100644 --- a/Utils.ps1 +++ b/Utils.ps1 @@ -1,3 +1,6 @@ +# Need this variable as long as we support PS v2 +$ModuleBasePath = Split-Path $MyInvocation.MyCommand.Path -Parent + # General Utility Functions function Invoke-NullCoalescing { @@ -27,42 +30,78 @@ function Invoke-Utf8ConsoleCommand([ScriptBlock]$cmd) { } } -function Add-ImportModuleToProfile { - param ( - [Parameter(Position = 0, Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $ProfilePath, - - # This is only required to support PS v2 there $PSScriptRoot only works in a .psm1 file - [Parameter(Position = 1, Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $ModuleBasePath - ) +<# +.SYNOPSIS + Configures your PowerShell profile (startup) script to import the posh-git + module when PowerShell starts. +.DESCRIPTION + Checks if your PowerShell profile script is not already importing posh-git + and if not, adds a command to import the posh-git module. This will cause + PowerShell to load posh-git whenever PowerShell starts. + imprt +.PARAMETER AllHosts + By default, this command modifies the CurrentUserCurrentHost profile + script. By specifying the AllHosts switch, the command updates the + CurrentUserAllHosts profile. +.PARAMETER Force + Do not check if the specified profile script is already importing + posh-git. Just add Import-Module posh-git command. +.EXAMPLE + PS C:\> Add-PoshGitToProfile + Updates your profile script for the current PowerShell host to import the + posh-git module when the current PowerShell host starts. +.EXAMPLE + PS C:\> Add-PoshGitToProfile -AllHost + Updates your profile script for all PowerShell hosts to import the posh-git + module whenever any PowerShell host starts. +.INPUTS + None. +.OUTPUTS + None. +#> +function Add-PoshGitToProfile([switch]$AllHosts, [switch]$Force) { + $underTest = $false - # Check if profile script exists - if (Test-Path -LiteralPath $profilePath) { - $profileContent = @(Get-Content -LiteralPath $profilePath) - $profileContent += [string]::Empty # Empty line between previous profile script and import statement - $encoding = Get-FileEncoding $profilePath + $profilePath = if ($AllHosts) { $PROFILE.CurrentUserAllHosts } else { $PROFILE.CurrentUserCurrentHost } + if ($args -gt 0) { + $profilePath = [string]$args[0] + $underTest = $true } - else { - # Doesn't exist, so create it - New-Item -Path $profilePath -ItemType File - $profileContent = @() - $encoding = 'utf8' + + if (!$Force) { + # Search the user's profiles to see if any are using posh-git already, there is an extra search + # ($profilePath) taking place to accomodate the Pester tests. + $importedInProfile = Test-PoshGitImportedInScript $profilePath + if (!$importedInProfile -and !$underTest) { + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserCurrentHost + } + if (!$importedInProfile -and !$underTest) { + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserAllHosts + } + if (!$importedInProfile -and !$underTest) { + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.AllUsersCurrentHost + } + if (!$importedInProfile -and !$underTest) { + $importedInProfile = Test-PoshGitImportedInScript $PROFILE.AllUsersAllHosts + } + + if ($importedInProfile) { + Write-Warning "Skipping add of posh-git import to file '$profilePath'." + Write-Warning "posh-git appears to already be imported in one of your profile scripts." + Write-Warning "If you want to force the add, use the -Force parameter." + return + } } # Check if the location of this module file is in the PSModulePath if (Test-InPSModulePath $ModuleBasePath) { - $profileContent += "Import-Module posh-git" + $profileContent = "`nImport-Module posh-git" } else { - $profileContent += "Import-Module '$ModuleBasePath\posh-git.psd1'" + $profileContent = "`nImport-Module '$ModuleBasePath\posh-git.psd1'" } - Set-Content -LiteralPath $profilePath -Value $profileContent -Encoding $encoding + Add-Content -LiteralPath $profilePath -Value $profileContent -Encoding UTF8 } <# diff --git a/posh-git.psd1 b/posh-git.psd1 index d94163aa5..ec084aa4a 100644 --- a/posh-git.psd1 +++ b/posh-git.psd1 @@ -24,6 +24,7 @@ PowerShellVersion = '2.0' # Functions to export from this module FunctionsToExport = @( 'Invoke-NullCoalescing', + 'Add-PoshGitToProfile', 'Write-GitStatus', 'Write-Prompt', 'Write-VcsStatus', diff --git a/posh-git.psm1 b/posh-git.psm1 index fc1840582..aefea93c0 100644 --- a/posh-git.psm1 +++ b/posh-git.psm1 @@ -1,4 +1,4 @@ -param([switch]$NoVersionWarn, [switch]$NoProfileCheck) +param([switch]$NoVersionWarn) if (Get-Module posh-git) { return } @@ -37,9 +37,8 @@ else { $poshGitPromptScriptBlock = $null $currentPromptDef = if ($funcInfo = Get-Command prompt -ErrorAction SilentlyContinue) { $funcInfo.Definition } - -# HACK: If prompt is missing, create a global one we can overwrite with Set-Item if (!$currentPromptDef) { + # HACK: If prompt is missing, create a global one we can overwrite with Set-Item function global:prompt { ' ' } } @@ -92,51 +91,6 @@ if (!$currentPromptDef -or ($currentPromptDef -eq $defaultPromptDef)) { Set-Item Function:\prompt -Value $poshGitPromptScriptBlock } -# IFF running interactive, check if user wants their profile script to be modified to import the module -if (!$NoProfileCheck -and ($stack = Get-PSCallStack) -and ($stack.Count -eq 2)) { - # Search the user's profiles to see if any are using posh-git already - $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserCurrentHost - if (!$importedInProfile) { - $importedInProfile = Test-PoshGitImportedInScript $PROFILE.CurrentUserAllHosts - } - if (!$importedInProfile) { - $importedInProfile = Test-PoshGitImportedInScript $PROFILE.AllUsersCurrentHost - } - if (!$importedInProfile) { - $importedInProfile = Test-PoshGitImportedInScript $PROFILE.AllUsersAllHosts - } - - # If we haven't detected that a profile script is using posh-git, ask if they want their profile modified to import posh-git - if (!$importedInProfile) { - $yesCurrent = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList @( - "&Yes, for the current PowerShell host", - "Modify the profile for $($Host.Name) to automatically import posh-git." - ) - - $yesAll = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList @( - "Yes, for &all PowerShell hosts", - "Modify the profile for all hosts to automatically import posh-git." - ) - - $no = New-Object System.Management.Automation.Host.ChoiceDescription -ArgumentList @( - "&No", - "Do not modify my profile. To suppress this prompt in the future, execute: Import-Module posh-git -Arg `$false, `$true" - ) - - $options = [System.Management.Automation.Host.ChoiceDescription[]]($yesCurrent, $yesAll, $no) - - $title = "Modify Profile" - $message = "Do you want posh-git to modify your profile to automatically import this module whenever your start PowerShell?" - $result = $host.UI.PromptForChoice($title, $message, $options, 0) - switch ($result) { - 0 { Add-ImportModuleToProfile $PROFILE.CurrentUserCurrentHost $PSScriptRoot } - 1 { Add-ImportModuleToProfile $PROFILE.CurrentUserAllHosts $PSScriptRoot } - 2 { } # Nothing to do if user picks 'No' - default { throw "Unexpected choice result: $result" } - } - } -} - # Install handler for removal/unload of the module $ExecutionContext.SessionState.Module.OnRemove = { $global:VcsPromptStatuses = $global:VcsPromptStatuses | Where-Object { $_ -ne $PoshGitVcsPrompt } @@ -155,6 +109,7 @@ $exportModuleMemberParams = @{ Alias = @('??') # TODO: Remove in 1.0.0 Function = @( 'Invoke-NullCoalescing', + 'Add-PoshGitToProfile', 'Write-GitStatus', 'Write-Prompt', 'Write-VcsStatus', diff --git a/test/Shared.ps1 b/test/Shared.ps1 index 408e49042..9488c65ae 100644 --- a/test/Shared.ps1 +++ b/test/Shared.ps1 @@ -1 +1 @@ -Import-Module $PSScriptRoot\..\posh-git.psd1 +$module = Import-Module $PSScriptRoot\..\posh-git.psd1 -PassThru diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index c827e6c88..8b738593a 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -1,7 +1,7 @@ . $PSScriptRoot\..\Utils.ps1 Describe 'Utils Function Tests' { - Context 'Add-ImportModuleToProfile Tests' { + Context 'Add-PoshGitToProfile Tests' { BeforeAll { $newLine = [System.Environment]::NewLine } @@ -14,13 +14,13 @@ Describe 'Utils Function Tests' { It 'Creates profile file if it does not exist' { Remove-Item -LiteralPath $profilePath Test-Path -LiteralPath $profilePath | Should Be $false - $scriptRoot = Split-Path $profilePath -Parent - Add-ImportModuleToProfile $profilePath $scriptRoot + Add-PoshGitToProfile $profilePath Test-Path -LiteralPath $profilePath | Should Be $true Get-FileEncoding $profilePath | Should Be 'utf8' $content = Get-Content $profilePath - $content.Count | Should Be 1 - @($content)[0] | Should BeExactly "Import-Module '$scriptRoot\posh-git.psd1'" + $content.Count | Should Be 2 + $modulePath = Resolve-Path $PSScriptRoot\.. + @($content)[1] | Should BeExactly "Import-Module '$modulePath\posh-git.psd1'" } It 'Modifies existing (Unicode) profile file correctly' { $profileContent = @' @@ -29,13 +29,13 @@ Import-Module PSCX New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win-core\bin\Debug\netcoreapp1.1\win10-x64\powershell.exe '@ Set-Content $profilePath -Value $profileContent -Encoding Unicode - $scriptRoot = Split-Path $profilePath -Parent - Add-ImportModuleToProfile $profilePath $scriptRoot + Add-PoshGitToProfile $profilePath Test-Path -LiteralPath $profilePath | Should Be $true Get-FileEncoding $profilePath | Should Be 'unicode' $content = Get-Content $profilePath $content.Count | Should Be 5 - $profileContent += "${newLine}${newLine}Import-Module '$scriptRoot\posh-git.psd1'" + $modulePath = Resolve-Path $PSScriptRoot\.. + $profileContent += "${newLine}${newLine}Import-Module '$modulePath\posh-git.psd1'" $content -join $newLine | Should BeExactly $profileContent } } From 539f714da7061f37e42ee32508231f47dfc59572 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Wed, 11 Jan 2017 23:18:15 -0700 Subject: [PATCH 9/9] Do not use Get-Module -List posh-git. Not reliable on PS v2. Add tests. --- Utils.ps1 | 14 +++++++--- test/Utils.Tests.ps1 | 65 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/Utils.ps1 b/Utils.ps1 index 5589c44e7..0154c8968 100644 --- a/Utils.ps1 +++ b/Utils.ps1 @@ -63,9 +63,14 @@ function Add-PoshGitToProfile([switch]$AllHosts, [switch]$Force) { $underTest = $false $profilePath = if ($AllHosts) { $PROFILE.CurrentUserAllHosts } else { $PROFILE.CurrentUserCurrentHost } - if ($args -gt 0) { + + # Under test, we override some variables using $args as a backdoor. + if ($args.Count -gt 0) { $profilePath = [string]$args[0] $underTest = $true + if ($args.Count -gt 1) { + $ModuleBasePath = [string]$args[1] + } } if (!$Force) { @@ -175,8 +180,9 @@ function Get-LocalOrParentPath($path) { return $null } -function Get-PoshGitModulePath { - Get-Module posh-git -ListAvailable | ForEach-Object { $_.ModuleBase } +function Get-PSModulePath { + $modulePaths = $Env:PSModulePath -split ';' + $modulePaths } function Test-InPSModulePath { @@ -187,7 +193,7 @@ function Test-InPSModulePath { $Path ) - $modulePaths = Get-PoshGitModulePath + $modulePaths = Get-PSModulePath if (!$modulePaths) { return $false } $pathStringComparison = Get-PathStringComparison diff --git a/test/Utils.Tests.ps1 b/test/Utils.Tests.ps1 index 8b738593a..c14ea2ba6 100644 --- a/test/Utils.Tests.ps1 +++ b/test/Utils.Tests.ps1 @@ -11,10 +11,12 @@ Describe 'Utils Function Tests' { AfterEach { Remove-Item $profilePath -ErrorAction SilentlyContinue } - It 'Creates profile file if it does not exist' { + It 'Creates profile file if it does not exist that imports absolute path' { Remove-Item -LiteralPath $profilePath Test-Path -LiteralPath $profilePath | Should Be $false + Add-PoshGitToProfile $profilePath + Test-Path -LiteralPath $profilePath | Should Be $true Get-FileEncoding $profilePath | Should Be 'utf8' $content = Get-Content $profilePath @@ -22,20 +24,57 @@ Describe 'Utils Function Tests' { $modulePath = Resolve-Path $PSScriptRoot\.. @($content)[1] | Should BeExactly "Import-Module '$modulePath\posh-git.psd1'" } - It 'Modifies existing (Unicode) profile file correctly' { + It 'Creates profile file if it does not exist that imports from module path' { + $parentDir = Split-Path $profilePath -Parent + Mock Get-PSModulePath { + return @( + 'C:\Users\Keith\Documents\WindowsPowerShell\Modules', + 'C:\Program Files\WindowsPowerShell\Modules', + 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\', + "$parentDir") + } + + Remove-Item -LiteralPath $profilePath + Test-Path -LiteralPath $profilePath | Should Be $false + + Add-PoshGitToProfile $profilePath $parentDir + + Test-Path -LiteralPath $profilePath | Should Be $true + Get-FileEncoding $profilePath | Should Be 'utf8' + $content = Get-Content $profilePath + $content.Count | Should Be 2 + @($content)[1] | Should BeExactly "Import-Module posh-git" + } + It 'Does not modify profile that already refers to posh-git' { + $profileContent = @' +Import-Module PSCX +Import-Module posh-git +'@ + Set-Content $profilePath -Value $profileContent -Encoding Ascii + + $output = Add-PoshGitToProfile $profilePath 3>&1 + + $output[1] | Should Match 'posh-git appears' + Get-FileEncoding $profilePath | Should Be 'ascii' + $content = Get-Content $profilePath + $content.Count | Should Be 2 + $content -join $newLine | Should BeExactly $profileContent + } + It 'Adds import from PSModulePath on existing (Unicode) profile file correctly' { $profileContent = @' Import-Module PSCX New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win-core\bin\Debug\netcoreapp1.1\win10-x64\powershell.exe '@ Set-Content $profilePath -Value $profileContent -Encoding Unicode - Add-PoshGitToProfile $profilePath + + Add-PoshGitToProfile $profilePath (Split-Path $profilePath -Parent) + Test-Path -LiteralPath $profilePath | Should Be $true Get-FileEncoding $profilePath | Should Be 'unicode' $content = Get-Content $profilePath $content.Count | Should Be 5 - $modulePath = Resolve-Path $PSScriptRoot\.. - $profileContent += "${newLine}${newLine}Import-Module '$modulePath\posh-git.psd1'" + $profileContent += "${newLine}${newLine}Import-Module posh-git" $content -join $newLine | Should BeExactly $profileContent } } @@ -66,36 +105,36 @@ New-Alias pscore C:\Users\Keith\GitHub\rkeithhill\PowerShell\src\powershell-win- Context 'Test-InPSModulePath Tests' { It 'Returns false for install not under any PSModulePaths' { - Mock Get-PoshGitModulePath { } + Mock Get-PSModulePath { } $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" Test-InPSModulePath $path | Should Be $false - Assert-MockCalled Get-PoshGitModulePath + Assert-MockCalled Get-PSModulePath } It 'Returns true for install under single PSModulePath' { - Mock Get-PoshGitModulePath { + Mock Get-PSModulePath { return 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0' } $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" Test-InPSModulePath $path | Should Be $true - Assert-MockCalled Get-PoshGitModulePath + Assert-MockCalled Get-PSModulePath } It 'Returns true for install under multiple PSModulePaths' { - Mock Get-PoshGitModulePath { + Mock Get-PSModulePath { return 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0', 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.6.1.20160330' } $path = "C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0" Test-InPSModulePath $path | Should Be $true - Assert-MockCalled Get-PoshGitModulePath + Assert-MockCalled Get-PSModulePath } It 'Returns false when current posh-git module location is not under PSModulePaths' { - Mock Get-PoshGitModulePath { + Mock Get-PSModulePath { return 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.7.0', 'C:\Users\Keith\Documents\WindowsPowerShell\Modules\posh-git\0.6.1.20160330' } $path = "C:\tools\posh-git\dahlbyk-posh-git-18d600a" Test-InPSModulePath $path | Should Be $false - Assert-MockCalled Get-PoshGitModulePath + Assert-MockCalled Get-PSModulePath } } }