MSI: Make sure that file components are patchable (#6303)

MSI: Make sure that file components are patchable
- avoid changing names and guids of components between builds as this prevents patch generation
- This required submitting the file generated by heat
- add code to make sure the generated file is not out of date
This commit is contained in:
Travis Plunk
2018-03-06 10:13:26 -08:00
committed by GitHub
parent 20b0e9cc61
commit da905f891b
3 changed files with 2495 additions and 20 deletions
+17 -16
View File
@@ -16,6 +16,7 @@
<?define ProductSemanticVersionWithNameAndOptionalArchitecture = "$(var.ProductName) $(env.ProductSemanticVersion) ($(sys.BUILDARCH))"?>
<?define ExplorerContextMenuDialogText = "&$(var.ProductName) $(env.ProductSemanticVersion) ($(sys.BUILDARCH))"?>
<?endif?>
<?define ProductDirectoryName = "$(env.ProductDirectoryName)" ?>
<?define ProductVersion = "$(env.ProductVersion)" ?>
<?define ProductSemanticVersion = "$(env.ProductSemanticVersion)" ?>
<?define ProductVersionWithName = "$(var.ProductName)_$(var.ProductVersion)"?>
@@ -41,13 +42,13 @@
<WixVariable Id="WixUIInfoIco" Value="assets\WixUIInfoIco.bmp" />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Open $(env.ProductName)" />
<!-- Default value of Checkbox of starting PowerShell after installation -->
<Property Id="WixShellExecTarget" Value="[$(var.ProductVersionWithName)]pwsh.exe"/>
<Property Id="WixShellExecTarget" Value="[$(var.ProductDirectoryName)]pwsh.exe"/>
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<SetProperty Id="RegisterManifest"
Before="RegisterManifest"
Sequence="execute"
Value="&quot;[$(var.ProductVersionWithName)]pwsh.exe&quot; -NoProfile -ExecutionPolicy Bypass -File &quot;[$(var.ProductVersionWithName)]RegisterManifest.ps1&quot;" />
Value="&quot;[$(var.ProductDirectoryName)]pwsh.exe&quot; -NoProfile -ExecutionPolicy Bypass -File &quot;[$(var.ProductDirectoryName)]RegisterManifest.ps1&quot;" />
<CustomAction Id="RegisterManifest"
BinaryKey="WixCA"
DllEntry="CAQuietExec"
@@ -57,7 +58,7 @@
<SetProperty Id="EnablePSRemoting"
Before="EnablePSRemoting"
Sequence="execute"
Value="&quot;[$(var.ProductVersionWithName)]pwsh.exe&quot; -NoProfile -ExecutionPolicy Bypass -Command &quot;Enable-PSRemoting&quot;" />
Value="&quot;[$(var.ProductDirectoryName)]pwsh.exe&quot; -NoProfile -ExecutionPolicy Bypass -Command &quot;Enable-PSRemoting&quot;" />
<CustomAction Id="EnablePSRemoting"
BinaryKey="WixCA"
DllEntry="CAQuietExec"
@@ -109,7 +110,7 @@
<UIRef Id="CustomWixUI_InstallDir" />
<!-- Features are mandatory. Need At Least One. -->
<Feature Id="ProductFeature" Title="PowerShell" Level="1">
<ComponentGroupRef Id="$(var.ProductVersionWithName)"/>
<ComponentGroupRef Id="$(var.ProductDirectoryName)"/>
<ComponentRef Id="ProductVersionFolder"/>
<ComponentRef Id="ApplicationProgramsMenuShortcut"/>
<ComponentRef Id="RegistryEntries"/>
@@ -141,7 +142,7 @@
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.ProductProgFilesDir)">
<Directory Id="INSTALLFOLDER" Name="PowerShell">
<Directory Id="$(var.ProductVersionWithName)" Name="$(var.ProductSemanticVersion)">
<Directory Id="$(var.ProductDirectoryName)" Name="$(var.ProductSemanticVersion)">
<Component Id="ProductVersionFolder" Guid="{e1a7f05e-0cd6-4227-80a8-e4fb311f045c}">
<CreateFolder/>
</Component>
@@ -153,7 +154,7 @@
</RegistryKey>
<!-- register ourselves in application registry so can be started using just Win+R `pwsh.exe` -->
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\pwsh.exe" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Value="[$(var.ProductVersionWithName)]pwsh.exe"/>
<RegistryValue Type="string" Value="[$(var.ProductDirectoryName)]pwsh.exe"/>
</RegistryKey>
</Component>
<!-- add ourselves to %PATH% so pwsh.exe can be started from Windows PowerShell or cmd.exe -->
@@ -167,42 +168,42 @@
<!-- When clicking on background in Explorer -->
<RegistryKey Root="HKCR" Key="Directory\Background\shell\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)">
<RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductVersionWithName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductDirectoryName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)"/>
</RegistryKey>
<!-- When clicking on Drive in Explorer -->
<RegistryKey Root="HKCR" Key="Drive\shell\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)">
<RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductVersionWithName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductDirectoryName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)"/>
</RegistryKey>
<!-- When clicking on Desktop background in Explorer -->
<RegistryKey Root="HKCR" Key="DesktopBackground\shell\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)">
<RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductVersionWithName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductDirectoryName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)"/>
</RegistryKey>
<!-- When clicking on folder in Explorer -->
<RegistryKey Root="HKCR" Key="Directory\shell\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)">
<RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextMenuDialogText)"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductVersionWithName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductDirectoryName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="ExtendedSubCommandsKey" Value="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)"/>
</RegistryKey>
<!-- Sub menus to open PowerShell at the current location either as a normal shell or as Administrator -->
<RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)\shell\open">
<RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextSubMenuDialogText)"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductVersionWithName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductDirectoryName)]assets\Powershell_black.ico"/>
</RegistryKey>
<RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)\shell\open\command">
<RegistryValue Type="string" Value="[$(var.ProductVersionWithName)]pwsh.exe -NoExit -Command Set-Location -LiteralPath '%V'"/>
<RegistryValue Type="string" Value="[$(var.ProductDirectoryName)]pwsh.exe -NoExit -Command Set-Location -LiteralPath '%V'"/>
</RegistryKey>
<RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)\shell\runas">
<RegistryValue Type="string" Name="MUIVerb" Value="$(var.ExplorerContextSubMenuElevatedDialogText)"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductVersionWithName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Name="Icon" Value="[$(var.ProductDirectoryName)]assets\Powershell_black.ico"/>
<RegistryValue Type="string" Value="" Name="HasLUAShield"/>
</RegistryKey>
<RegistryKey Root="HKCR" Key="Directory\ContextMenus\$(var.ProductName)$(env.ProductSemanticVersion)$(sys.BUILDARCH)\shell\runas\command">
<RegistryValue Type="string" Value="[$(var.ProductVersionWithName)]pwsh.exe -NoExit -Command Set-Location -LiteralPath '%V'"/>
<RegistryValue Type="string" Value="[$(var.ProductDirectoryName)]pwsh.exe -NoExit -Command Set-Location -LiteralPath '%V'"/>
</RegistryKey>
</Component>
</Directory>
@@ -214,8 +215,8 @@
<Shortcut Id="PowerShell_ProgramsMenuShortcut"
Name="$(var.ProductSemanticVersionWithNameAndOptionalArchitecture)"
Description="$(var.ProductSemanticVersionWithNameAndOptionalArchitecture)"
Target="[$(var.ProductVersionWithName)]pwsh.exe"
WorkingDirectory="$(var.ProductVersionWithName)"
Target="[$(var.ProductDirectoryName)]pwsh.exe"
WorkingDirectory="$(var.ProductDirectoryName)"
Icon = "PowerShellExe.ico" />
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<!-- HKMU is HKLM when installing perMachine and HKCU when installing perUser-->
+2406
View File
File diff suppressed because it is too large Load Diff
+72 -4
View File
@@ -2050,6 +2050,11 @@ function New-MSIPackage
[ValidateScript( {Test-Path $_})]
[string] $ProductWxsPath = "$PSScriptRoot\..\..\assets\Product.wxs",
# File describing the MSI file components
[ValidateNotNullOrEmpty()]
[ValidateScript( {Test-Path $_})]
[string] $FilesWxsPath = "$PSScriptRoot\..\..\assets\Files.wxs",
# Path to Assets folder containing artifacts such as icons, images
[ValidateNotNullOrEmpty()]
[ValidateScript( {Test-Path $_})]
@@ -2100,11 +2105,13 @@ function New-MSIPackage
$productVersionWithName = $ProductName + '_' + $ProductVersion
$productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion
$productDirectoryName = 'PowerShell_6'
Write-Verbose "Create MSI for Product $productSemanticVersionWithName"
[Environment]::SetEnvironmentVariable("ProductSourcePath", $ProductSourcePath, "Process")
# These variables are used by Product.wxs in assets directory
[Environment]::SetEnvironmentVariable("ProductDirectoryName", $productDirectoryName, "Process")
[Environment]::SetEnvironmentVariable("ProductName", $ProductName, "Process")
[Environment]::SetEnvironmentVariable("ProductCode", $ProductCode, "Process")
[Environment]::SetEnvironmentVariable("ProductVersion", $ProductVersion, "Process")
@@ -2130,7 +2137,7 @@ function New-MSIPackage
$wixFragmentPath = Join-Path $env:Temp "Fragment.wxs"
$wixObjProductPath = Join-Path $env:Temp "Product.wixobj"
$wixObjFragmentPath = Join-Path $env:Temp "Fragment.wixobj"
$wixObjFragmentPath = Join-Path $env:Temp "files.wixobj"
# cleanup any garbage on the system
Remove-Item -ErrorAction SilentlyContinue $wixFragmentPath -Force
@@ -2149,11 +2156,12 @@ function New-MSIPackage
Write-Error -Message "Package already exists, use -Force to overwrite, path: $msiLocationPath" -ErrorAction Stop
}
log "running heat..."
Start-NativeExecution -VerboseOutputOnError { & $wixHeatExePath dir $ProductSourcePath -dr $productVersionWithName -cg $productVersionWithName -gg -sfrag -srd -scom -sreg -out $wixFragmentPath -var env.ProductSourcePath -v}
log "verifying no new files have been added or removed..."
Start-NativeExecution -VerboseOutputOnError { & $wixHeatExePath dir $ProductSourcePath -dr $productDirectoryName -cg $productDirectoryName -gg -sfrag -srd -scom -sreg -out $wixFragmentPath -var env.ProductSourcePath -v}
Test-FileWxs -FilesWxsPath $FilesWxsPath -HeatFilesWxsPath $wixFragmentPath
log "running candle..."
Start-NativeExecution -VerboseOutputOnError { & $wixCandleExePath "$ProductWxsPath" "$wixFragmentPath" -out (Join-Path "$env:Temp" "\\") -ext WixUIExtension -ext WixUtilExtension -arch $ProductTargetArchitecture -v}
Start-NativeExecution -VerboseOutputOnError { & $wixCandleExePath "$ProductWxsPath" "$FilesWxsPath" -out (Join-Path "$env:Temp" "\\") -ext WixUIExtension -ext WixUtilExtension -arch $ProductTargetArchitecture -v}
log "running light..."
# suppress ICE61, because we allow same version upgrades
@@ -2184,6 +2192,66 @@ function New-MSIPackage
}
}
# verify no files have been added or removed
# if so, write an error with details
function Test-FileWxs
{
param
(
# File describing the MSI file components from the asset folder
[ValidateNotNullOrEmpty()]
[ValidateScript( {Test-Path $_})]
[string] $FilesWxsPath = "$PSScriptRoot\..\..\assets\Files.wxs",
# File describing the MSI file components generated by heat
[ValidateNotNullOrEmpty()]
[ValidateScript( {Test-Path $_})]
[string] $HeatFilesWxsPath
)
[xml] $filesAssetXml = Get-Content -Raw -Path $FilesWxsPath
[xml] $heatFilesXml = Get-Content -Raw -Path $HeatFilesWxsPath
$assetFiles = $filesAssetXml.GetElementsByTagName('File')
$heatFiles = $heatFilesXml.GetElementsByTagName('File')
$indexedHeatFiles = @()
# Index the list of files generated by heat
foreach($file in $heatFiles)
{
$indexedHeatFiles += $file.Source
}
# Index the files from the asset wxs
# and verify that no files have been removed.
$passed = $true
$indexedAssetFiles = @()
foreach($file in $assetFiles)
{
$name = $file.Source
if($indexedHeatFiles -inotcontains $name)
{
$passed = $false
Write-Warning "{$name} is no longer in product and should be removed from {$FilesWxsPath}"
}
$indexedAssetFiles += $name
}
# verify that no files have been added.
foreach($file in $indexedHeatFiles)
{
if($indexedAssetFiles -inotcontains $file)
{
$passed = $false
Write-Warning "new file {$file} need to be added to {$FilesWxsPath}"
}
}
if(!$passed)
{
throw "Current files to not match {$FilesWxsPath}"
}
}
# Builds coming out of this project can have version number as 'a.b.c' OR 'a.b.c-d-f'
# This function converts the above version into major.minor[.build[.revision]] format
function Get-PackageVersionAsMajorMinorBuildRevision