diff --git a/Scenarios.md b/Scenarios.md index c9767724fb..011ebfa259 100644 --- a/Scenarios.md +++ b/Scenarios.md @@ -1,6 +1,6 @@ ## Chocolatey Usage Scenarios -### ChocolateyInstallCommand [ 35 Scenario(s), 293 Observation(s) ] +### ChocolateyInstallCommand [ 42 Scenario(s), 312 Observation(s) ] #### when force installing a package that depends on an unavailable newer version of an installed dependency forcing dependencies @@ -247,6 +247,20 @@ * should not install a package in the lib directory * should put a package in the lib bad directory +#### when installing a package that tries to overwrite another shim + + * should have a shim + * should have a shim with target in other package tools folder + * should have an error message + * should have shim target + +#### when installing a package that tries to overwrite its own shim + + * should create a shim + * should have a shim with target in tools folder + * should have an error message + * should have shim targets + #### when installing a package with a dependent package that also depends on a less constrained but still valid dependency of the same package * [PENDING] should contain a message that everything installed successfully @@ -282,6 +296,18 @@ * should not install a package in the lib directory * should not install the dependency in the lib directory +#### when installing a package with dependencies and noshims + + * should create a shim for the dependency + * should have shim targets + * should not create a shim for the package + +#### when installing a package with dependencies and noshimsglobal + + * should have shim targets + * should not create a shim for the dependency + * should not create a shim for the package + #### when installing a package with dependencies happy * should contain a message that everything installed successfully @@ -326,11 +352,25 @@ * [PENDING] should not install the conflicting package in the lib directory * [PENDING] should not upgrade the exact version dependency +#### when installing a package with install bin file + + * should not see the shim as an existing shim and remove it + +#### when installing a package with install bin file and noshims + + * should have shim target + * should not create a shim + #### when installing a package with no sources enabled * should have no sources enabled result * should not install any packages +#### when installing a package with noshims + + * should have shim target + * should not create a shim for the package + #### when installing a side by side package * config should match package result name @@ -541,7 +581,7 @@ * should contain success message -### ChocolateyUninstallCommand [ 13 Scenario(s), 93 Observation(s) ] +### ChocolateyUninstallCommand [ 14 Scenario(s), 95 Observation(s) ] #### when force uninstalling a package @@ -617,6 +657,11 @@ * should not remove package from the lib directory * should still have the package file in the directory +#### when uninstalling a package that forgets to call uninstall bin file + + * should have had a shim + * should have removed the shim + #### when uninstalling a package with a read and delete share locked file * should contain a message that it uninstalled successfully @@ -675,7 +720,7 @@ * should throw an error that it is not allowed -### ChocolateyUpgradeCommand [ 36 Scenario(s), 295 Observation(s) ] +### ChocolateyUpgradeCommand [ 40 Scenario(s), 307 Observation(s) ] #### when force upgrading a package @@ -920,6 +965,11 @@ * should have no sources enabled result * should not have any packages upgraded +#### when upgrading a package with noshims + + * should have shim target + * should not create a shim + #### when upgrading a package with readonly files * should contain a warning message that it upgraded successfully @@ -933,6 +983,25 @@ * should upgrade the package * should upgrade where install location reports +#### when upgrading a package with shims + + * should create a shim + * should have had original shim + * should have shim target + * should not have original shim + +#### when upgrading a package with shims that errors + + * should have original shim + * should not create a shim + +#### when upgrading a package with shims with noshims + + * should have had original shim + * should have shim target + * should not create a shim + * should not have original shim + #### when upgrading a package with unavailable dependencies * should contain a message that it was unable to upgrade anything diff --git a/src/chocolatey.resources/helpers/functions/Install-BinFile.ps1 b/src/chocolatey.resources/helpers/functions/Install-BinFile.ps1 index 972b432fca..eff970dfbf 100644 --- a/src/chocolatey.resources/helpers/functions/Install-BinFile.ps1 +++ b/src/chocolatey.resources/helpers/functions/Install-BinFile.ps1 @@ -86,6 +86,13 @@ param( Write-FunctionCallLogMessage -Invocation $MyInvocation -Parameters $PSBoundParameters + if ($env:ChocolateyNoShims) { + Write-Debug "File shimming disabled for `'$($env:ChocolateyPackageName)`'." + Write-Debug "Removing any existing shim for `'$name`'." + Uninstall-BinFile $name $path + return + } + $nugetPath = [System.IO.Path]::GetFullPath((Join-Path "$helpersPath" '..\')) $nugetExePath = Join-Path "$nugetPath" 'bin' $packageBatchFileName = Join-Path $nugetExePath "$name.bat" diff --git a/src/chocolatey.tests.integration/Scenario.cs b/src/chocolatey.tests.integration/Scenario.cs index 4077b192f9..d40dd87cae 100644 --- a/src/chocolatey.tests.integration/Scenario.cs +++ b/src/chocolatey.tests.integration/Scenario.cs @@ -177,6 +177,8 @@ private static ChocolateyConfiguration baseline_configuration() config.PinCommand.Name = string.Empty; config.PinCommand.Command = PinCommandType.unknown; config.ListCommand.IdOnly = false; + config.NoShims = false; + config.NoShimsGlobal = false; return config; } diff --git a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj index aaf566b4d4..23f26ddfbf 100644 --- a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj +++ b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj @@ -346,6 +346,105 @@ Always + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + Always diff --git a/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/shimbasepackage.nuspec b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/shimbasepackage.nuspec new file mode 100644 index 0000000000..b620fe06cd --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/shimbasepackage.nuspec @@ -0,0 +1,17 @@ + + + + shimbasepackage + 1.0.0 + shimbasepackage + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + __REPLACE__ + __REPLACE__ + shimbasepackage + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..5cc9f79b7a --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Installed" diff --git a/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..6489cba588 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/shimbasepackage1.exe b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/shimbasepackage1.exe new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimbasepackage/1.0.0/tools/shimbasepackage1.exe @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/shimhasdependency.nuspec b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/shimhasdependency.nuspec new file mode 100644 index 0000000000..342b618af3 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/shimhasdependency.nuspec @@ -0,0 +1,20 @@ + + + + shimhasdependency + 1.0.0 + shimhasdependency + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + __REPLACE__ + __REPLACE__ + shimhasdependency + + + + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..5cc9f79b7a --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Installed" diff --git a/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..6489cba588 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/shimhasdependency1.exe b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/shimhasdependency1.exe new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimhasdependency/1.0.0/tools/shimhasdependency1.exe @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/shimoverwrite.nuspec b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/shimoverwrite.nuspec new file mode 100644 index 0000000000..3c52b00e54 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/shimoverwrite.nuspec @@ -0,0 +1,17 @@ + + + + shimoverwrite + 1.0.0 + shimoverwrite + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + __REPLACE__ + __REPLACE__ + overwrite-own + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..5cc9f79b7a --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Installed" diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..6489cba588 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/install/shimoverwrite1.exe b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/install/shimoverwrite1.exe new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/install/shimoverwrite1.exe @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/shimoverwrite1.exe b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/shimoverwrite1.exe new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwrite/1.0.0/tools/shimoverwrite1.exe @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/shimoverwriteother.nuspec b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/shimoverwriteother.nuspec new file mode 100644 index 0000000000..e8941cd7bf --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/shimoverwriteother.nuspec @@ -0,0 +1,20 @@ + + + + shimoverwriteother + 1.0.0 + shimoverwriteother + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + __REPLACE__ + __REPLACE__ + shimoverwriteother + + + + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..5cc9f79b7a --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Installed" diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..6489cba588 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/shimbasepackage1.exe b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/shimbasepackage1.exe new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimoverwriteother/1.0.0/tools/shimbasepackage1.exe @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/shimupgrade.nuspec b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/shimupgrade.nuspec new file mode 100644 index 0000000000..ef00377e59 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/shimupgrade.nuspec @@ -0,0 +1,17 @@ + + + + shimupgrade + 1.0.0 + shimupgrade + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + __REPLACE__ + __REPLACE__ + shimupgrade + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..5cc9f79b7a --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Installed" diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..6489cba588 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/shimupgrade1.exe b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/shimupgrade1.exe new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/1.0.0/tools/shimupgrade1.exe @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/shimupgrade.nuspec b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/shimupgrade.nuspec new file mode 100644 index 0000000000..c4213d5185 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/shimupgrade.nuspec @@ -0,0 +1,17 @@ + + + + shimupgrade + 2.0.0 + shimupgrade + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + This version throws an error when installing + __REPLACE__ + shimupgrade + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..9b17e662f9 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1,7 @@ +try { + Write-Output "This is $packageName v$packageVersion being installed to `n '$packageFolder'." + Write-Error "Oh no! An error" + throw "We had an error captain!" +} catch { + throw $_.Exception +} diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..6489cba588 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/shimupgrade2.exe b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/shimupgrade2.exe new file mode 100644 index 0000000000..359a5b952d --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/2.0.0/tools/shimupgrade2.exe @@ -0,0 +1 @@ +2.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/shimupgrade.nuspec b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/shimupgrade.nuspec new file mode 100644 index 0000000000..7559fd0990 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/shimupgrade.nuspec @@ -0,0 +1,17 @@ + + + + shimupgrade + 3.0.0 + shimupgrade + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + __REPLACE__ + __REPLACE__ + shimupgrade + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..5cc9f79b7a --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Installed" diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..6489cba588 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1 @@ +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/shimupgrade3.exe b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/shimupgrade3.exe new file mode 100644 index 0000000000..56fea8a08d --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimupgrade/3.0.0/tools/shimupgrade3.exe @@ -0,0 +1 @@ +3.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/shimwithbinfile.nuspec b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/shimwithbinfile.nuspec new file mode 100644 index 0000000000..ec1d5047f5 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/shimwithbinfile.nuspec @@ -0,0 +1,17 @@ + + + + shimwithbinfile + 1.0.0 + shimwithbinfile + __REPLACE_AUTHORS_OF_SOFTWARE__ + __REPLACE_YOUR_NAME__ + false + This version forgets to call Uninstall-BinFile when uninstalling + __REPLACE__ + shimwithbinfile + + + + + diff --git a/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/chocolateyInstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/chocolateyInstall.ps1 new file mode 100644 index 0000000000..6e9af8f601 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/chocolateyInstall.ps1 @@ -0,0 +1,7 @@ +$ErrorActionPreference = 'Stop' + +$toolsDir = Split-Path $MyInvocation.MyCommand.Definition +$filePath = Join-Path $toolsDir "shimwithbinfile1.bat" + +Install-Binfile "shimwithbinfile1" "$filePath" +Write-Output "$env:PackageName $env:PackageVersion Installed" diff --git a/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/chocolateyUninstall.ps1 b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/chocolateyUninstall.ps1 new file mode 100644 index 0000000000..f329925b82 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/chocolateyUninstall.ps1 @@ -0,0 +1,4 @@ +$ErrorActionPreference = 'Stop' + +Write-Output "Oops, we've forgotten to call 'Uninstall-BinFile `"shimwithbinfile1`"'" +Write-Output "$env:PackageName $env:PackageVersion Uninstalled" diff --git a/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/shimwithbinfile1.bat b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/shimwithbinfile1.bat new file mode 100644 index 0000000000..afaf360d37 --- /dev/null +++ b/src/chocolatey.tests.integration/context/shims/shimwithbinfile/1.0.0/tools/shimwithbinfile1.bat @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/src/chocolatey.tests.integration/scenarios/InstallScenarios.cs b/src/chocolatey.tests.integration/scenarios/InstallScenarios.cs index f0856ff6ac..f20a54e192 100644 --- a/src/chocolatey.tests.integration/scenarios/InstallScenarios.cs +++ b/src/chocolatey.tests.integration/scenarios/InstallScenarios.cs @@ -3391,5 +3391,372 @@ public void should_not_install_any_packages() Results.Count().ShouldEqual(0); } } + + [Concern(typeof(ChocolateyInstallCommand))] + public class when_installing_a_package_with_noshims : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PackageNames = Configuration.Input = "shimbasepackage"; + Scenario.add_packages_to_source_location(Configuration, "shimbasepackage.1.0.0*" + Constants.PackageExtension); + Configuration.NoShims = true; + } + + public override void Because() + { + Service.install_run(Configuration); + } + + [Fact] + public void should_have_shim_target() + { + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + var target = Path.Combine(packageDir, "tools", "shimbasepackage1.exe"); + + File.Exists(target).ShouldBeTrue(); + } + + [Fact] + public void should_not_create_a_shim_for_the_package() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimbasepackage1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + } + + [Concern(typeof(ChocolateyInstallCommand))] + public class when_installing_a_package_with_dependencies_and_noshims : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PackageNames = Configuration.Input = "shimhasdependency"; + Scenario.add_packages_to_source_location(Configuration, "shimhasdependency.1.0.0*" + Constants.PackageExtension); + Scenario.add_packages_to_source_location(Configuration, "shimbasepackage.1.0.0*" + Constants.PackageExtension); + Configuration.NoShims = true; + } + + public override void Because() + { + Results = Service.install_run(Configuration); + } + + [Fact] + public void should_have_shim_targets() + { + var targetsExist = true; + var errorMessage = string.Empty; + + foreach (var packageResult in Results) + { + var target = Path.Combine(packageResult.Value.InstallLocation, "tools", packageResult.Value.Name + "1.exe"); + + if (!File.Exists(target)) + { + targetsExist = false; + errorMessage = "Target file missing: {0}".format_with(target); + break; + } + } + + targetsExist.ShouldBeTrue(errorMessage); + } + + [Fact] + public void should_not_create_a_shim_for_the_package() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimhasdependency1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + + [Fact] + public void should_create_a_shim_for_the_dependency() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimbasepackage1.exe"); + + File.Exists(shimfile).ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyInstallCommand))] + public class when_installing_a_package_with_dependencies_and_noshimsglobal : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PackageNames = Configuration.Input = "shimhasdependency"; + Scenario.add_packages_to_source_location(Configuration, "shimhasdependency.1.0.0*" + Constants.PackageExtension); + Scenario.add_packages_to_source_location(Configuration, "shimbasepackage.1.0.0*" + Constants.PackageExtension); + Configuration.NoShimsGlobal = true; + } + + public override void Because() + { + Results = Service.install_run(Configuration); + } + + [Fact] + public void should_have_shim_targets() + { + var targetsExist = true; + var errorMessage = string.Empty; + + foreach (var packageResult in Results) + { + var target = Path.Combine(packageResult.Value.InstallLocation, "tools", packageResult.Value.Name + "1.exe"); + + if (!File.Exists(target)) + { + targetsExist = false; + errorMessage = "Target file missing: {0}".format_with(target); + break; + } + } + + targetsExist.ShouldBeTrue(errorMessage); + } + + [Fact] + public void should_not_create_a_shim_for_the_package() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimhasdependency1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + + [Fact] + public void should_not_create_a_shim_for_the_dependency() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimbasepackage1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + } + + [Concern(typeof(ChocolateyInstallCommand))] + public class when_installing_a_package_with_install_bin_file : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PackageNames = Configuration.Input = "shimwithbinfile"; + Scenario.add_packages_to_source_location(Configuration, "shimwithbinfile.1.0.0*" + Constants.PackageExtension); + } + + public override void Because() + { + Service.install_run(Configuration); + } + + [Fact] + public void should_not_see_the_shim_as_an_existing_shim_and_remove_it() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimwithbinfile1.exe"); + + File.Exists(shimfile).ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyInstallCommand))] + public class when_installing_a_package_with_install_bin_file_and_noshims : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PackageNames = Configuration.Input = "shimwithbinfile"; + Scenario.add_packages_to_source_location(Configuration, "shimwithbinfile.1.0.0*" + Constants.PackageExtension); + Configuration.NoShims = true; + } + + public override void Because() + { + Service.install_run(Configuration); + } + + [Fact] + public void should_have_shim_target() + { + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + var target = Path.Combine(packageDir, "tools", "shimwithbinfile1.bat"); + + File.Exists(target).ShouldBeTrue(); + } + + [Fact] + public void should_not_create_a_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimwithbinfile1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + } + + [Concern(typeof(ChocolateyInstallCommand))] + public class when_installing_a_package_that_tries_to_overwrite_its_own_shim : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PackageNames = Configuration.Input = "shimoverwrite"; + Scenario.add_packages_to_source_location(Configuration, "shimoverwrite.1.0.0*" + Constants.PackageExtension); + } + + public override void Because() + { + Service.install_run(Configuration); + } + + [Fact] + public void should_have_shim_targets() + { + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + var toolsPath = Path.Combine(packageDir, "tools"); + + string[] targets = { + Path.Combine(toolsPath, "shimoverwrite1.exe"), + Path.Combine(toolsPath, "install", "shimoverwrite1.exe") + }; + + var targetsExist = true; + var errorMessage = string.Empty; + + foreach (string target in targets) + { + if (!File.Exists(target)) + { + targetsExist = false; + errorMessage = "Target file missing: {0}".format_with(target); + break; + } + } + + targetsExist.ShouldBeTrue(errorMessage); + } + + [Fact] + public void should_have_an_error_message() + { + bool expectedMessage = false; + foreach (var message in MockLogger.MessagesFor(LogLevel.Error).or_empty_list_if_null()) + { + if (message.Contains("cannot overwrite")) expectedMessage = true; + } + + expectedMessage.ShouldBeTrue(); + } + + [Fact] + public void should_create_a_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimoverwrite1.exe"); + + File.Exists(shimfile).ShouldBeTrue(); + } + + [Fact] + public void should_have_a_shim_with_target_in_tools_folder() + { + var messages = new List(); + + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimoverwrite1.exe"); + CommandExecutor.execute( + shimfile, + "--shimgen-noop", + 10, + stdOutAction: (s, e) => messages.Add(e.Data), + stdErrAction: (s, e) => messages.Add(e.Data) + ); + + var messageFound = false; + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + var path = Path.Combine(packageDir, "tools", "shimoverwrite1.exe"); + + foreach (var message in messages.or_empty_list_if_null()) + { + if (string.IsNullOrWhiteSpace(message)) continue; + if (message.Contains(path)) messageFound = true; + } + + messageFound.ShouldBeTrue("Target file message not found for: {0}".format_with(path)); + } + } + + [Concern(typeof(ChocolateyInstallCommand))] + public class when_installing_a_package_that_tries_to_overwrite_another_shim : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PackageNames = Configuration.Input = "shimoverwriteother"; + Scenario.add_packages_to_source_location(Configuration, "shimoverwriteother.1.0.0*" + Constants.PackageExtension); + Scenario.add_packages_to_source_location(Configuration, "shimbasepackage.1.0.0*" + Constants.PackageExtension); + } + + public override void Because() + { + Service.install_run(Configuration); + } + + [Fact] + public void should_have_shim_target() + { + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + + // this matches the name of the existing shim from the shimbasepackage dependency + var target = Path.Combine(packageDir, "tools", "shimbasepackage1.exe"); + + File.Exists(target).ShouldBeTrue(); + } + + [Fact] + public void should_have_an_error_message() + { + bool expectedMessage = false; + foreach (var message in MockLogger.MessagesFor(LogLevel.Error).or_empty_list_if_null()) + { + if (message.Contains("cannot overwrite")) expectedMessage = true; + } + + expectedMessage.ShouldBeTrue(); + } + + [Fact] + public void should_have_a_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimbasepackage1.exe"); + + File.Exists(shimfile).ShouldBeTrue(); + } + + [Fact] + public void should_have_a_shim_with_target_in_other_package_tools_folder() + { + var messages = new List(); + + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimbasepackage1.exe"); + CommandExecutor.execute( + shimfile, + "--shimgen-noop", + 10, + stdOutAction: (s, e) => messages.Add(e.Data), + stdErrAction: (s, e) => messages.Add(e.Data) + ); + + var messageFound = false; + var dependencyDir = Path.Combine(Scenario.get_top_level(), "lib", "shimbasepackage"); + var path = Path.Combine(dependencyDir, "tools", "shimbasepackage1.exe"); + + foreach (var message in messages.or_empty_list_if_null()) + { + if (string.IsNullOrWhiteSpace(message)) continue; + if (message.Contains(path)) messageFound = true; + } + + messageFound.ShouldBeTrue("Target file message not found for: {0}".format_with(path)); + } + } } } diff --git a/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs b/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs index 2279bb3ff1..6471a8ce78 100644 --- a/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs +++ b/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs @@ -1047,5 +1047,43 @@ public void should_have_expected_error_in_package_result() errorFound.ShouldBeTrue(); } } + + [Concern(typeof(ChocolateyUninstallCommand))] + public class when_uninstalling_a_package_that_forgets_to_call_uninstall_bin_file : ScenariosBase + { + private string shimFile; + private bool shimExisted; + + public override void Context() + { + Configuration = Scenario.upgrade(); + Scenario.reset(Configuration); + Service = NUnitSetup.Container.GetInstance(); + + Configuration.PackageNames = Configuration.Input = "shimwithbinfile"; + Scenario.add_packages_to_source_location(Configuration, Configuration.Input + "*" + Constants.PackageExtension); + Scenario.install_package(Configuration, "shimwithbinfile", "1.0.0"); + } + + public override void Because() + { + shimFile = Path.Combine(Scenario.get_top_level(), "bin", "shimwithbinfile1.exe"); + shimExisted = File.Exists(shimFile); + + Service.uninstall_run(Configuration); + } + + [Fact] + public void should_have_had_a_shim() + { + shimExisted.ShouldBeTrue(shimFile); + } + + [Fact] + public void should_have_removed_the_shim() + { + File.Exists(shimFile).ShouldBeFalse(); + } + } } } diff --git a/src/chocolatey.tests.integration/scenarios/UpgradeScenarios.cs b/src/chocolatey.tests.integration/scenarios/UpgradeScenarios.cs index b9e152fcb0..b4ac0752a8 100644 --- a/src/chocolatey.tests.integration/scenarios/UpgradeScenarios.cs +++ b/src/chocolatey.tests.integration/scenarios/UpgradeScenarios.cs @@ -3182,5 +3182,207 @@ public void should_skip_packages_in_except_list() upgradePackageResult.Count.ShouldEqual(0, "upgradepackage should not be in the results list"); } } + + [Concern(typeof(ChocolateyUpgradeCommand))] + public class when_upgrading_a_package_with_noshims : ScenariosBase + { + public override void Context() + { + Configuration = Scenario.upgrade(); + Scenario.reset(Configuration); + Service = NUnitSetup.Container.GetInstance(); + + Configuration.PackageNames = Configuration.Input = "shimupgrade"; + Scenario.add_packages_to_source_location(Configuration, Configuration.Input + "*" + Constants.PackageExtension); + Configuration.Version = "1.0.0"; + Configuration.NoShims = true; + } + + public override void Because() + { + Service.upgrade_run(Configuration); + } + + [Fact] + public void should_have_shim_target() + { + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + var target = Path.Combine(packageDir, "tools", "shimupgrade1.exe"); + + File.Exists(target).ShouldBeTrue(); + } + + [Fact] + public void should_not_create_a_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + } + + [Concern(typeof(ChocolateyUpgradeCommand))] + public class when_upgrading_a_package_with_shims_that_errors : ScenariosBase + { + public override void Context() + { + Configuration = Scenario.upgrade(); + Scenario.reset(Configuration); + Service = NUnitSetup.Container.GetInstance(); + + Configuration.PackageNames = Configuration.Input = "shimupgrade"; + Scenario.add_packages_to_source_location(Configuration, Configuration.Input + "*" + Constants.PackageExtension); + Scenario.install_package(Configuration, "shimupgrade", "1.0.0"); + + // version 2.0.0 errors on script install + Configuration.Version = "2.0.0"; + } + + public override void Because() + { + Service.upgrade_run(Configuration); + } + + [Fact] + public void should_have_original_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade1.exe"); + + File.Exists(shimfile).ShouldBeTrue(); + } + + [Fact] + public void should_not_create_a_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade2.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + } + + [Concern(typeof(ChocolateyUpgradeCommand))] + public class when_upgrading_a_package_with_shims : ScenariosBase + { + private string _original_shim = string.Empty; + private bool _original_shim_existed = false; + + public override void Context() + { + Configuration = Scenario.upgrade(); + Scenario.reset(Configuration); + Service = NUnitSetup.Container.GetInstance(); + + Configuration.PackageNames = Configuration.Input = "shimupgrade"; + Scenario.add_packages_to_source_location(Configuration, Configuration.Input + "*" + Constants.PackageExtension); + Scenario.install_package(Configuration, "shimupgrade", "1.0.0"); + + _original_shim = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade1.exe"); + _original_shim_existed = File.Exists(_original_shim); + + // version 3.0.0 is okay + Configuration.Version = "3.0.0"; + } + + public override void Because() + { + Service.upgrade_run(Configuration); + } + + [Fact] + public void should_have_had_original_shim() + { + var errorMessage = "Original shim file was not created: {0}".format_with(_original_shim); + + _original_shim_existed.ShouldBeTrue(errorMessage); + } + + [Fact] + public void should_have_shim_target() + { + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + var target = Path.Combine(packageDir, "tools", "shimupgrade3.exe"); + + File.Exists(target).ShouldBeTrue(); + } + + [Fact] + public void should_not_have_original_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + + [Fact] + public void should_create_a_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade3.exe"); + + File.Exists(shimfile).ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyUpgradeCommand))] + public class when_upgrading_a_package_with_shims_with_noshims : ScenariosBase + { + private string _original_shim = string.Empty; + private bool _original_shim_existed = false; + + public override void Context() + { + Configuration = Scenario.upgrade(); + Scenario.reset(Configuration); + Service = NUnitSetup.Container.GetInstance(); + + Configuration.PackageNames = Configuration.Input = "shimupgrade"; + Scenario.add_packages_to_source_location(Configuration, Configuration.Input + "*" + Constants.PackageExtension); + Scenario.install_package(Configuration, "shimupgrade", "1.0.0"); + + _original_shim = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade1.exe"); + _original_shim_existed = File.Exists(_original_shim); + + // version 3.0.0 is okay + Configuration.Version = "3.0.0"; + Configuration.NoShims = true; + } + + public override void Because() + { + Service.upgrade_run(Configuration); + } + + [Fact] + public void should_have_had_original_shim() + { + var errorMessage = "Original shim file was not created: {0}".format_with(_original_shim); + + _original_shim_existed.ShouldBeTrue(errorMessage); + } + + [Fact] + public void should_have_shim_target() + { + var packageDir = Path.Combine(Scenario.get_top_level(), "lib", Configuration.PackageNames); + var target = Path.Combine(packageDir, "tools", "shimupgrade3.exe"); + + File.Exists(target).ShouldBeTrue(); + } + + [Fact] + public void should_not_have_original_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade1.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + + [Fact] + public void should_not_create_a_shim() + { + var shimfile = Path.Combine(Scenario.get_top_level(), "bin", "shimupgrade3.exe"); + + File.Exists(shimfile).ShouldBeFalse(); + } + } } } diff --git a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyInstallCommandSpecs.cs b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyInstallCommandSpecs.cs index f32acfd5e6..5ff6ddc5c9 100644 --- a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyInstallCommandSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyInstallCommandSpecs.cs @@ -235,6 +235,18 @@ public void should_add_short_version_of_password_to_the_option_set() { optionSet.Contains("p").ShouldBeTrue(); } + + [Fact] + public void should_add_noshims_to_the_option_set() + { + optionSet.Contains("noshims").ShouldBeTrue(); + } + + [Fact] + public void should_add_noshimsglobal_to_the_option_set() + { + optionSet.Contains("noshimsglobal").ShouldBeTrue(); + } } public class when_handling_additional_argument_parsing : ChocolateyInstallCommandSpecsBase diff --git a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUpgradeCommandSpecs.cs b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUpgradeCommandSpecs.cs index 15f16f875f..41dc123fdb 100644 --- a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUpgradeCommandSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyUpgradeCommandSpecs.cs @@ -217,6 +217,18 @@ public void should_add_short_version_of_password_to_the_option_set() { optionSet.Contains("p").ShouldBeTrue(); } + + [Fact] + public void should_add_noshims_to_the_option_set() + { + optionSet.Contains("noshims").ShouldBeTrue(); + } + + [Fact] + public void should_add_noshimsglobal_to_the_option_set() + { + optionSet.Contains("noshimsglobal").ShouldBeTrue(); + } } public class when_handling_additional_argument_parsing : ChocolateyUpgradeCommandSpecsBase diff --git a/src/chocolatey/chocolatey.csproj b/src/chocolatey/chocolatey.csproj index f1d4e6bc7e..6e88de73e8 100644 --- a/src/chocolatey/chocolatey.csproj +++ b/src/chocolatey/chocolatey.csproj @@ -134,6 +134,9 @@ + + + diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs index ba9cf33556..1c2fcc5669 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs @@ -180,6 +180,12 @@ public virtual void configure_argument_parser(OptionSet optionSet, ChocolateyCon configuration.Features.UsePackageRepositoryOptimizations = false; } }) + .Add("noshims|no-shims", + "No Shims - Stop shims being created for the package. Defaults to false. Available in 0.10.16+.", + option => configuration.NoShims = option != null) + .Add("noshimsglobal|no-shims-global", + "No Shims Global - Stop shims being created for the package and its dependencies. Defaults to false. Available in 0.10.16+.", + option => configuration.NoShimsGlobal = option != null) ; //todo: package name can be a url / installertype diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs index f8a4c31f6a..64e061ee1e 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs @@ -220,6 +220,12 @@ public virtual void configure_argument_parser(OptionSet optionSet, ChocolateyCon configuration.Features.UsePackageRepositoryOptimizations = false; } }) + .Add("noshims|no-shims", + "No Shims - Stop shims being created for the package. Defaults to false. Available in 0.10.16+.", + option => configuration.NoShims = option != null) + .Add("noshimsglobal|no-shims-global", + "No Shims Global - Stop shims being created for the package and its dependencies. Defaults to false. Available in 0.10.16+.", + option => configuration.NoShimsGlobal = option != null) ; } diff --git a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs index c5cc33f73f..13f842977e 100644 --- a/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs +++ b/src/chocolatey/infrastructure.app/configuration/ChocolateyConfiguration.cs @@ -221,6 +221,8 @@ private void append_output(StringBuilder propertyValues, string append) public string DownloadChecksum64 { get; set; } public string DownloadChecksumType { get; set; } public string DownloadChecksumType64 { get; set; } + public bool NoShims { get; set; } + public bool NoShimsGlobal { get; set; } /// /// Configuration values provided by choco. diff --git a/src/chocolatey/infrastructure.app/domain/ShimRecord.cs b/src/chocolatey/infrastructure.app/domain/ShimRecord.cs new file mode 100644 index 0000000000..370ade1e27 --- /dev/null +++ b/src/chocolatey/infrastructure.app/domain/ShimRecord.cs @@ -0,0 +1,60 @@ +// Copyright © 2017 - 2018 Chocolatey Software, Inc +// Copyright © 2011 - 2017 RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.infrastructure.app.domain +{ + public class ShimRecord + { + /// + /// The exe file from the shim directory. + /// + public string ExeFile { get; set; } + + /// + /// The package name (could be empty). + /// + public string PackageName { get; set; } + + /// + /// The file being shimmed (could be empty). + /// + public string TargetFile { get; set; } + + /// + /// Creates a ShimRecord instance. + /// + /// The exe file from the shim directory. + public ShimRecord(string exeFile) + { + ExeFile = exeFile; + PackageName = string.Empty; + TargetFile = string.Empty; + } + + /// + /// Creates a ShimRecord instance. + /// + /// The exe file from the shim directory. + /// The package name. + /// The file being shimmed. + public ShimRecord(string exeFile, string packageName, string targetFile) + { + ExeFile = exeFile; + PackageName = packageName; + TargetFile = targetFile; + } + } +} diff --git a/src/chocolatey/infrastructure.app/domain/ShimRegistry.cs b/src/chocolatey/infrastructure.app/domain/ShimRegistry.cs new file mode 100644 index 0000000000..2df0f79600 --- /dev/null +++ b/src/chocolatey/infrastructure.app/domain/ShimRegistry.cs @@ -0,0 +1,306 @@ +// Copyright © 2017 - 2018 Chocolatey Software, Inc +// Copyright © 2011 - 2017 RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.infrastructure.app.domain +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Text; + using System.Text.RegularExpressions; + using filesystem; + + public class ShimRegistry + { + private readonly IFileSystem _fileSystem; + private readonly string _shimsLocation; + private readonly string _packagesLocation; + private readonly string _pathRoot; + private readonly Regex _packageRegex; + private ShimStore _store; + + /// + /// The level required when accessing the data. + /// + public enum DataLevel + { + Current, + Latest + } + + /// + /// Creates a ShimRegistry instance. + /// + /// The file system. + public ShimRegistry(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + _shimsLocation = ApplicationParameters.ShimsLocation; + _packagesLocation = ApplicationParameters.PackagesLocation; + _pathRoot = Path.GetPathRoot(_shimsLocation); + _packageRegex = new Regex(@"{0}\\(.[^\\]+)\\".format_with(_packagesLocation.Replace(@"\", @"\\")), + RegexOptions.Compiled | RegexOptions.IgnoreCase); + } + + /// + /// Adds a shim to the store. + /// + /// The shim exe file. + /// The package name. + /// The file being shimmed. + public void add(string exeFile, string packageName, string targetFile) + { + ensure_storage_exists(DataLevel.Current); + var record = new ShimRecord(exeFile, packageName, targetFile); + _store.add_record(record); + } + + /// + /// Gets a shim record from the store it if exists. + /// + /// The shim exe file. + /// The record or null. + public ShimRecord get(string exeFile) + { + ensure_storage_exists(DataLevel.Current); + return _store.get_record(exeFile); + } + + /// + /// Updates the store from the file system. + /// + public void create_snapshot() + { + ensure_storage_exists(DataLevel.Latest); + } + + /// + /// Returns all shim records for the package. + /// + /// The package name. + /// The shim records. + public IList get_all(string packageName) + { + ensure_storage_exists(DataLevel.Latest); + return _store.get_all_records(packageName); + } + + /// + /// Returns all shim records for the package that have not been modified. + /// + /// The package name. + /// The unmodified shim records. + public IList get_snapshot(string packageName) + { + ensure_storage_exists(DataLevel.Current); + var exeFiles = get_shim_exe_files(); + + return _store.get_snapshot_records(exeFiles, packageName); + } + + /// + /// Removes a shim from the store. + /// + /// The shim exe file. + public void remove(string exeFile) + { + ensure_storage_exists(DataLevel.Current); + _store.remove_record(exeFile); + } + + /// + /// Initializes or updates the store. + /// + /// The data level required. + private void ensure_storage_exists(DataLevel level) + { + if (_store == null) + { + init_store(); + } + else if (level == DataLevel.Latest) + { + update_store(); + } + } + + /// + /// Creates and initializes the store from the file system. + /// + private void init_store() + { + _store = new ShimStore(_fileSystem); + var exeFiles = get_shim_exe_files(); + + foreach (string file in exeFiles.or_empty_list_if_null()) + { + _store.add_record(get_shim_data(file)); + } + } + + /// + /// Updates the store from the file system. + /// + private void update_store() + { + var exeFiles = get_shim_exe_files(); + + foreach (string file in _store.get_files_to_update(exeFiles)) + { + _store.add_record(get_shim_data(file)); + } + } + + /// + /// Gets the exe files in the shim directory. + /// + /// The exe files. + private IEnumerable get_shim_exe_files() + { + return _fileSystem.get_files(_shimsLocation, pattern: "*.exe"); + } + + /// + /// Extracts any shim data from an exe file. + /// + /// The exe file + /// A record containing full or partial shim data. + private ShimRecord get_shim_data(string exeFile) + { + var item = new ShimRecord(exeFile); + + // check the exe is shimgen generated from the file info + FileVersionInfo info = FileVersionInfo.GetVersionInfo(exeFile); + + // note that this will not catch chocolatey specific shims + if (!info.ProductName.contains("shimgen")) return item; + + // extract the target file from the binary + string target = find_shim_target(exeFile); + + item.TargetFile = check_and_get_targetFile(target); + + // try and extract the package name + if (item.TargetFile.contains(_packagesLocation)) + { + var match = _packageRegex.Match(item.TargetFile).Groups[1]; + if (match != null) + { + item.PackageName = match.Value; + } + } + + return item; + } + + /// + /// Searches an exe file for the shim target file name. + /// + /// The exe file. + /// The target file name or null. + private string find_shim_target(string exeFile) + { + string target = null; + byte[] bytes = File.ReadAllBytes(exeFile); + + // search for the pattern: file at '' + int startIndex = 0; + string pattern = "file at '"; + int foundIndex = search_binary(bytes, pattern, startIndex); + + if (foundIndex == -1) + { + return target; + } + + // search for the closing single-quote + startIndex = foundIndex + (pattern.Length * 2); + pattern = "'"; + foundIndex = search_binary(bytes, pattern, startIndex); + + if (foundIndex != -1) + { + int count = foundIndex - startIndex; + var slice = new byte[count]; + Array.Copy(bytes, startIndex, slice, 0, count); + target = Encoding.Unicode.GetString(slice); + } + + return target; + } + + /// + /// Searches an array of bytes for a pattern. + /// + /// The array of bytes. + /// The pattern to search for. + /// The index to start searching from. + /// The index of the pattern or -1. + private int search_binary(byte[] bytes, string search, int startIndex) + { + int foundIndex = -1; + byte[] pattern = Encoding.Unicode.GetBytes(search); + int end = bytes.Length - pattern.Length + 1; + int i = startIndex; + int m = 0; + + while (i < end) + { + if (bytes[i] == pattern[m]) + { + ++m; + if (m == pattern.Length) { + foundIndex = i - pattern.Length + 1; + break; + } + } + else if (m > 0) + { + i -= m; + m = 0; + } + ++i; + } + + return foundIndex; + } + + /// + /// Checks that the extracted file name is valid. + /// + /// The target file name. + /// The fully qualified path or an empty string. + private string check_and_get_targetFile(string target) + { + if (string.IsNullOrEmpty(target)) return string.Empty; + + if (!target.Replace('/', '\\').StartsWith(_pathRoot, StringComparison.OrdinalIgnoreCase)) + { + target = _fileSystem.combine_paths(_packagesLocation, target); + } + + try + { + return _fileSystem.get_full_path(target); + } + catch + { + return string.Empty; + } + } + } +} diff --git a/src/chocolatey/infrastructure.app/domain/ShimStore.cs b/src/chocolatey/infrastructure.app/domain/ShimStore.cs new file mode 100644 index 0000000000..ce1f3ae335 --- /dev/null +++ b/src/chocolatey/infrastructure.app/domain/ShimStore.cs @@ -0,0 +1,260 @@ +// Copyright © 2017 - 2018 Chocolatey Software, Inc +// Copyright © 2011 - 2017 RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.infrastructure.app.domain +{ + using System; + using System.Collections.Generic; + using filesystem; + + public class ShimStore + { + private readonly IFileSystem _fileSystem; + private readonly IDictionary _items; + + public class BaseRecord + { + /// + /// The exe file from the shim directory. + /// + public string ExeFile { get; set; } + + /// + /// The package name (could be empty). + /// + public string PackageName { get; set; } + + /// + /// The file being shimmed (could be empty). + /// + public string TargetFile { get; set; } + + /// + /// ExeFile last modification time. + /// + public Int64 LastModified { get; set; } + + /// + /// Internal flag for synchronizing. + /// + public bool Current { get; set; } + + /// + /// Creates a BaseRecord instance. + /// + /// The data record. + /// Last modification time of the exe file. + public BaseRecord(ShimRecord record, Int64 lastModified) + { + ExeFile = record.ExeFile; + PackageName = record.PackageName; + TargetFile = record.TargetFile; + LastModified = lastModified; + Current = false; + } + } + + /// + /// Creates a ShimStore instance. + /// + /// The filesystem. + public ShimStore(IFileSystem filesystem) + { + _fileSystem = filesystem; + _items = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + /// + /// Adds a record to the store. + /// + /// The record. + public void add_record(ShimRecord record) + { + string key = get_key(record.ExeFile); + _items[key] = new BaseRecord(record, get_timestamp(record.ExeFile)); + } + + /// + /// Removes a record from the store. + /// + /// The exe file to remove. + public void remove_record(string exeFile) + { + string key = get_key(exeFile); + _items.Remove(key); + } + + /// + /// Gets a record from the store if it exsists. + /// + /// The exe file to get + /// The record or null. + public ShimRecord get_record(string exeFile) + { + BaseRecord record; + if (_items.TryGetValue(get_key(exeFile), out record)) + { + return new ShimRecord(record.ExeFile, record.PackageName, record.TargetFile); + } + + return null; + } + + /// + /// Synchronizes the store with the file system. + /// + /// The exe files in the shims directory. + /// A list of exe files that need adding or updating. + public IList get_files_to_update(IEnumerable exeFiles) + { + var updates = new List(); + BaseRecord record; + + // set found records as current and collect new or out-of-date ones + foreach (string file in exeFiles.or_empty_list_if_null()) + { + if (_items.TryGetValue(get_key(file), out record)) + { + if (get_timestamp(file) > record.LastModified) + { + updates.Add(file); + } + + record.Current = true; + } + else + { + updates.Add(file); + } + } + + remove_non_current(); + + return updates; + } + + /// + /// Returns all records for the package. + /// + /// The package name. + /// The list of records. + public IList get_all_records(string forPackage) + { + var records = new List(); + var values = _items.Values; + + foreach (BaseRecord record in values) + { + if (record.PackageName.Equals(forPackage, StringComparison.OrdinalIgnoreCase)) + { + records.Add(get_record_from_base(record)); + } + } + + return records; + } + + /// + /// Returns all records for the package that have not been modified. + /// + /// The exe files in the shims directory. + /// The package name. + /// The list of unmodified records. + public IList get_snapshot_records(IEnumerable exeFiles, string forPackage) + { + var records = new List(); + BaseRecord record; + + // set found records as current and collect non-changed items + foreach (string file in exeFiles.or_empty_list_if_null()) + { + if (_items.TryGetValue(get_key(file), out record)) + { + if (record.PackageName.Equals(forPackage, StringComparison.OrdinalIgnoreCase)) + { + if (get_timestamp(file) == record.LastModified) + { + records.Add(get_record_from_base(record)); + } + + } + + record.Current = true; + } + } + + remove_non_current(); + + return records; + } + + /// + /// Gets the storage key. + /// + /// The exe file. + /// The file name of the exe file. + private string get_key(string exeFile) + { + return _fileSystem.get_file_name(exeFile); + } + + /// + /// Create a ShimRecord from an internal base record. + /// + /// The internal base record. + /// The ShimRecord. + private ShimRecord get_record_from_base(BaseRecord record) + { + return new ShimRecord(record.ExeFile, record.PackageName, record.TargetFile); + } + + /// + /// Gets the timestamp of a file. + /// + /// The exe file. + /// The last modified UTC time. + private Int64 get_timestamp(string exeFile) + { + return _fileSystem.get_file_modified_date(exeFile).ToFileTimeUtc(); + } + + /// + /// Removes records marked as not current and resets the property. + /// + /// Only call this after setting the current records to true. + private void remove_non_current() + { + var removed = new List(); + + // collect the non-current records and reset property + foreach (KeyValuePair record in _items) + { + if (!record.Value.Current) + { + removed.Add(record.Key); + } + + record.Value.Current = false; + } + + // remove the non-current records + foreach (string key in removed) + { + _items.Remove(key); + } + } + } +} diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs index 0b4295d93d..231f577237 100644 --- a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs +++ b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs @@ -344,6 +344,9 @@ public virtual void handle_package_result(PackageResult packageResult, Chocolate if (packageResult.Success && config.Information.PlatformType == PlatformType.Windows) { + // take the snapshot before running any install/uninstall scripts + _shimgenService.take_snapshot(); + if (!config.SkipPackageInstallProvider) { var installersBefore = _registryService.get_installer_keys(); diff --git a/src/chocolatey/infrastructure.app/services/IShimGenerationService.cs b/src/chocolatey/infrastructure.app/services/IShimGenerationService.cs index c6916ed5c6..2878021490 100644 --- a/src/chocolatey/infrastructure.app/services/IShimGenerationService.cs +++ b/src/chocolatey/infrastructure.app/services/IShimGenerationService.cs @@ -16,6 +16,7 @@ namespace chocolatey.infrastructure.app.services { + using System.Collections.Generic; using configuration; using results; @@ -34,5 +35,10 @@ public interface IShimGenerationService /// The configuration. /// The package result. void uninstall(ChocolateyConfiguration configuration, PackageResult packageResult); + + /// + /// Takes a snapshot of the existing shimgens + /// + void take_snapshot(); } } diff --git a/src/chocolatey/infrastructure.app/services/PowershellService.cs b/src/chocolatey/infrastructure.app/services/PowershellService.cs index 653c22d5b7..faeb4341f6 100644 --- a/src/chocolatey/infrastructure.app/services/PowershellService.cs +++ b/src/chocolatey/infrastructure.app/services/PowershellService.cs @@ -398,11 +398,14 @@ public void prepare_powershell_environment(IPackage package, ChocolateyConfigura Environment.SetEnvironmentVariable("chocolateyChecksumType64", null); Environment.SetEnvironmentVariable("chocolateyForceX86", null); Environment.SetEnvironmentVariable("DownloadCacheAvailable", null); + Environment.SetEnvironmentVariable("chocolateyNoShims", null); + + var isDependency = PackageUtility.package_is_a_dependency(configuration, package.Id); // we only want to pass the following args to packages that would apply. // like choco install git --params '' should pass those params to git.install, // but not another package unless the switch apply-install-arguments-to-dependencies is used - if (!PackageUtility.package_is_a_dependency(configuration, package.Id) || configuration.ApplyInstallArgumentsToDependencies) + if (!isDependency || configuration.ApplyInstallArgumentsToDependencies) { this.Log().Debug(ChocolateyLoggers.Verbose, "Setting installer args for {0}".format_with(package.Id)); Environment.SetEnvironmentVariable("installArguments", configuration.InstallArguments); @@ -417,13 +420,20 @@ public void prepare_powershell_environment(IPackage package, ChocolateyConfigura // we only want to pass package parameters to packages that would apply. // but not another package unless the switch apply-package-parameters-to-dependencies is used - if (!PackageUtility.package_is_a_dependency(configuration, package.Id) || configuration.ApplyPackageParametersToDependencies) + if (!isDependency || configuration.ApplyPackageParametersToDependencies) { this.Log().Debug(ChocolateyLoggers.Verbose, "Setting package parameters for {0}".format_with(package.Id)); Environment.SetEnvironmentVariable("packageParameters", configuration.PackageParameters); Environment.SetEnvironmentVariable("chocolateyPackageParameters", configuration.PackageParameters); } + // we only want to disable shimming for packages that would apply. + if (configuration.NoShimsGlobal || (!isDependency && configuration.NoShims)) + { + this.Log().Debug(ChocolateyLoggers.Verbose, "Setting noshims for {0}".format_with(package.Id)); + Environment.SetEnvironmentVariable("chocolateyNoShims", "true"); + } + if (!string.IsNullOrWhiteSpace(configuration.DownloadChecksum)) { Environment.SetEnvironmentVariable("chocolateyChecksum32", configuration.DownloadChecksum); diff --git a/src/chocolatey/infrastructure.app/services/ShimGenerationService.cs b/src/chocolatey/infrastructure.app/services/ShimGenerationService.cs index 01d6991b24..24faecfbf6 100644 --- a/src/chocolatey/infrastructure.app/services/ShimGenerationService.cs +++ b/src/chocolatey/infrastructure.app/services/ShimGenerationService.cs @@ -1,13 +1,13 @@ // Copyright © 2017 - 2018 Chocolatey Software, Inc // Copyright © 2011 - 2017 RealDimensions Software, LLC -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -// +// // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,6 +21,8 @@ namespace chocolatey.infrastructure.app.services using System.IO; using configuration; using filesystem; + using infrastructure.app.domain; + using infrastructure.app.utility; using infrastructure.commands; using results; @@ -33,13 +35,14 @@ public class ShimGenerationService : IShimGenerationService private const string OUTPUT_TOKEN = "{{output}}"; private readonly string _shimGenExePath = ApplicationParameters.Tools.ShimGenExe; private readonly IDictionary _shimGenArguments = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - + private readonly ShimRegistry _registry; public ShimGenerationService(IFileSystem fileSystem, ICommandExecutor commandExecutor) { _fileSystem = fileSystem; _commandExecutor = commandExecutor; set_shimgen_args_dictionary(); + _registry = new ShimRegistry(_fileSystem); } /// @@ -87,15 +90,54 @@ public void install(ChocolateyConfiguration configuration, PackageResult package return; } - //gather all .exes in the folder - var exeFiles = _fileSystem.get_files(packageResult.InstallLocation, pattern: "*.exe", option: SearchOption.AllDirectories); - foreach (string file in exeFiles.or_empty_list_if_null()) + var existingShims = _registry.get_snapshot(packageResult.Name); + var noShims = is_shimming_disabled(configuration, packageResult); + + if (noShims) + { + this.Log().Debug(() => "Automatic package shimming disabled for {0}".format_with(packageResult.Name)); + } + + if (existingShims.Count > 0) + { + this.Log().Debug(() => "Removing previous shims for {0}".format_with(packageResult.Name)); + uninstall_shims(existingShims); + } + + if (!noShims) + { + //gather all relevant .exes in the folder + var exeFiles = get_exe_files_to_shim(packageResult.InstallLocation); + install_shims(configuration, packageResult.Name, exeFiles); + } + } + + public void uninstall(ChocolateyConfiguration configuration, PackageResult packageResult) + { + var existingShims = _registry.get_all(packageResult.Name); + uninstall_shims(existingShims); + } + + public void take_snapshot() + { + _registry.create_snapshot(); + } + + /// + /// Installs shimgens for the package + /// + /// The configuration. + /// The package name. + /// The exe files to shim + private void install_shims(ChocolateyConfiguration configuration, string packageName, IList exeFiles) + { + var args = ExternalCommandArgsBuilder.build_arguments(configuration, _shimGenArguments); + + foreach (string file in exeFiles) { - if (_fileSystem.file_exists(file + ".ignore")) continue; bool isGui = _fileSystem.file_exists(file + ".gui"); //todo: v2 be able to determine gui automatically - var args = ExternalCommandArgsBuilder.build_arguments(configuration, _shimGenArguments); var shimLocation = _fileSystem.combine_paths(ApplicationParameters.ShimsLocation, _fileSystem.get_file_name(file)); var argsForPackage = args.Replace(PATH_TOKEN, file.Replace(ApplicationParameters.InstallLocation, "..\\")).Replace(OUTPUT_TOKEN, shimLocation).Replace(ICON_PATH_TOKEN, file); if (isGui) @@ -103,18 +145,28 @@ public void install(ChocolateyConfiguration configuration, PackageResult package argsForPackage += " --gui"; } + // check for an existing shim + ShimRecord record = _registry.get(shimLocation); + if (record != null) + { + this.Log().Error(() => " ShimGen cannot overwrite shim {0} in {1} package".format_with(_fileSystem.get_file_name(file), record.PackageName)); + this.Log().Debug(() => " Shim: {0}{1} Target: {2}{1} New target: {3}{1}".format_with(shimLocation, Environment.NewLine, record.TargetFile, file)); + Environment.ExitCode = 1; + continue; + } + var exitCode = _commandExecutor.execute( _shimGenExePath, argsForPackage, configuration.CommandExecutionTimeoutSeconds, (s, e) => - { - if (string.IsNullOrWhiteSpace(e.Data)) return; - this.Log().Debug(() => " [ShimGen] {0}".format_with(e.Data.escape_curly_braces())); - }, + { + if (string.IsNullOrWhiteSpace(e.Data)) return; + this.Log().Debug(() => " [ShimGen] {0}".format_with(e.Data.escape_curly_braces())); + }, (s, e) => - { - if (string.IsNullOrWhiteSpace(e.Data)) return; - this.Log().Error(() => " [ShimGen] {0}".format_with(e.Data.escape_curly_braces())); - }, + { + if (string.IsNullOrWhiteSpace(e.Data)) return; + this.Log().Error(() => " [ShimGen] {0}".format_with(e.Data.escape_curly_braces())); + }, updateProcessPath: true ); @@ -124,24 +176,67 @@ public void install(ChocolateyConfiguration configuration, PackageResult package } else { + _registry.add(shimLocation, packageName, file); this.Log().Info(() => " ShimGen has successfully created a {0}shim for {1}".format_with(isGui ? "gui " : string.Empty, _fileSystem.get_file_name(file))); - this.Log().Debug(() => " Created: {0}{1} Targeting: {2}{1} IsGui:{3}{1}".format_with(shimLocation, Environment.NewLine, file, isGui)); + this.Log().Debug(() => " Created: {0}{1} Targeting: {2}{1} IsGui: {3}{1}".format_with(shimLocation, Environment.NewLine, file, isGui)); } } } - public void uninstall(ChocolateyConfiguration configuration, PackageResult packageResult) + /// + /// Uninstalls shimgens for the package + /// + /// The shim records for the package. + private void uninstall_shims(IList existingShims) { - //gather all .exes in the folder - var exeFiles = _fileSystem.get_files(packageResult.InstallLocation, pattern: "*.exe", option: SearchOption.AllDirectories); - foreach (string file in exeFiles.or_empty_list_if_null()) + foreach (ShimRecord record in existingShims) { - if (_fileSystem.file_exists(file + ".ignore")) continue; + this.Log().Debug(() => "Removing shim {0} targetting '{1}'".format_with(_fileSystem.get_file_name(record.ExeFile), record.TargetFile)); + _fileSystem.delete_file(record.ExeFile); - var shimLocation = _fileSystem.combine_paths(ApplicationParameters.ShimsLocation, _fileSystem.get_file_name(file)); - this.Log().Debug(() => "Removing shim for {0} at '{1}".format_with(_fileSystem.get_file_name(file), shimLocation)); - _fileSystem.delete_file(shimLocation); + if (!_fileSystem.file_exists(record.ExeFile)) + { + _registry.remove(record.ExeFile); + } } } + + /// + /// Returns the exe files to shim + /// + /// The package install location. + /// + private IList get_exe_files_to_shim(string installLocation) + { + var exeFiles = new List(); + + if (!_fileSystem.directory_exists(installLocation) || installLocation.is_equal_to(ApplicationParameters.InstallLocation) || installLocation.is_equal_to(ApplicationParameters.PackagesLocation)) + { + return exeFiles; + } + + var targetFiles = _fileSystem.get_files(installLocation, pattern: "*.exe", option: SearchOption.AllDirectories); + foreach (string file in targetFiles.or_empty_list_if_null()) + { + if (!_fileSystem.file_exists(file + ".ignore")) + { + exeFiles.Add(file); + } + } + + return exeFiles; + } + + /// + /// Checks if shimming is disabled for the package + /// + /// The configuration. + /// The package result. + /// true if shimming is disabled + private bool is_shimming_disabled(ChocolateyConfiguration configuration, PackageResult packageResult) + { + return configuration.NoShimsGlobal || (configuration.NoShims + && !PackageUtility.package_is_a_dependency(configuration, packageResult.Package.Id)); + } } -} \ No newline at end of file +}